Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/llnotes-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Release llnotes

on:
push:
tags:
- 'llnotes/v*'

jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: write
steps:
- uses: actions/checkout@v3

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: 1.21

- name: Build
run: /bin/bash .github/workflows/build.sh llnotes

- name: Compress
run: /bin/bash .github/workflows/compress.sh

- name: Create release
uses: softprops/action-gh-release@v1
with:
files: dist/*
51 changes: 51 additions & 0 deletions .github/workflows/push-llnotes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: build-llnotes

on:
pull_request:
types: [opened, synchronize]
paths: ['llnotes/**']

permissions:
id-token: write
contents: read
pull-requests: write

jobs:
tests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: 1.21
- name: Install Tools
run: go install gotest.tools/gotestsum@latest
- name: Test
working-directory: llnotes
run: make test

fmt:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: 1.21.0
- name: Install Tools
run: |
go install golang.org/x/tools/cmd/goimports@latest
go install honnef.co/go/tools/cmd/staticcheck@latest
- name: Run make fmt
working-directory: llnotes
run: make fmt
- name: Run go mod tidy
working-directory: llnotes
run: go mod tidy
- name: Fail on differences
run: |
# Exit with status code 1 if there are differences (i.e. unformatted files)
git diff --exit-code
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ fmt-go-libs:
fmt-acceptance:
cd acceptance && make fmt

fmt: fmt-acceptance fmt-go-libs
fmt-llnotes:
cd llnotes && make fmt

fmt: fmt-acceptance fmt-go-libs fmt-llnotes
9 changes: 8 additions & 1 deletion NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,11 @@ This Software contains code from the following projects, licensed under the BSD-

go-github
Copyright 2013 The go-github AUTHORS. All rights reserved.
License - https://github.com/google/go-github/blob/master/LICENSE
License - https://github.com/google/go-github/blob/master/LICENSE

This Software contains code from the following projects, licensed under the MIT license:

go-diff
Copyright (c) 2014 Sourcegraph, Inc.
Copyright (c) 2012 Matias Bordese
https://github.com/sourcegraph/go-diff/blob/master/LICENSE
1 change: 1 addition & 0 deletions go-libs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ coverage: test

vendor:
@echo "✓ Filling vendor folder with library code ..."
@go mod tidy
@go mod vendor

.PHONY: build vendor coverage test fmt
7 changes: 7 additions & 0 deletions go-libs/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,13 @@ func (c *GitHubClient) ListCommits(ctx context.Context, org, repo string, req *L
})
}

func (c *GitHubClient) GetCommit(ctx context.Context, org, repo string, sha string) (*RepositoryCommit, error) {
var res RepositoryCommit
path := fmt.Sprintf("%s/repos/%s/%s/commits/%s", gitHubAPI, org, repo, sha)
err := c.api.Do(ctx, "GET", path, httpclient.WithResponseUnmarshal(&res))
return &res, err
}

func (c *GitHubClient) CompareCommits(ctx context.Context, org, repo, base, head string) listing.Iterator[RepositoryCommit] {
type response struct {
Commits []RepositoryCommit `json:"commits,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions go-libs/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/fatih/color v1.16.0
github.com/google/go-querystring v1.1.0
github.com/nwidger/jsoncolor v0.3.2
github.com/sourcegraph/go-diff v0.7.0
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.18.2
Expand Down
4 changes: 4 additions & 0 deletions go-libs/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,12 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=
github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
Expand Down
59 changes: 59 additions & 0 deletions go-libs/llnotes/announce.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package llnotes

import (
"context"
"fmt"
"strings"

"github.com/databricks/databricks-sdk-go/listing"
"github.com/databricks/databricks-sdk-go/logger"
)

var blogPrompt = MessageTemplate(`Do not hallucinate.
You are professional technical writer and you receive draft release notes for {{.version}} of project called {{.repo.Name}} in a markdown format from multiple team members.
Project can be described as "{{.repo.Description}}"

You write a long post announcement that takes at least 5 minutes to read, summarize the most important features, and mention them on top. Keep the markdown links when relevant.
Do not use headings. Write fluent paragraphs, that are at least few sentences long. Blog post title should nicely summarize the feature increments of this release.

Don't abuse lists. paragraphs should have at least 3-4 sentences. The title should be one-sentence summary of the incremental updates for this release

You aim at driving more adoption of the project on Medium.`)

func (lln *llNotes) versionNotes(ctx context.Context, newVersion string) ([]string, error) {
versions, err := listing.ToSlice(ctx, lln.gh.Versions(ctx, lln.org, lln.repo))
if err != nil {
return nil, fmt.Errorf("versions: %w", err)
}
if newVersion == "" {
newVersion = versions[0].Version
}
prevVersion := "v0.0.0"
for i, v := range versions {
if v.Version == newVersion {
prevVersion = versions[i+1].Version
break
}
}
return lln.ReleaseNotesDiff(ctx, prevVersion, newVersion)
}

func (lln *llNotes) Announce(ctx context.Context, newVersion string) (History, error) {
notes, err := lln.versionNotes(ctx, newVersion)
if err != nil {
return nil, fmt.Errorf("parallel: %w", err)
}
repo, err := lln.gh.GetRepo(ctx, lln.org, lln.repo)
if err != nil {
return nil, fmt.Errorf("get repo: %w", err)
}
rawNotes := strings.Join(notes, "\n")
logger.Debugf(ctx, "Raw notes: %s", rawNotes)
return lln.Talk(ctx, History{
blogPrompt.AsSystem(map[string]any{
"version": newVersion,
"repo": repo,
}),
UserMessage(rawNotes),
})
}
115 changes: 115 additions & 0 deletions go-libs/llnotes/chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package llnotes

import (
"fmt"
"strings"

"github.com/databricks/databricks-sdk-go/service/serving"
"github.com/databrickslabs/sandbox/go-libs/sed"
)

type message interface {
ChatMessage() serving.ChatMessage
}

type SystemMessage string

func (m SystemMessage) ChatMessage() serving.ChatMessage {
return serving.ChatMessage{
Role: serving.ChatMessageRoleSystem,
Content: string(m),
}
}

type UserMessage string

func (m UserMessage) ChatMessage() serving.ChatMessage {
return serving.ChatMessage{
Role: serving.ChatMessageRoleUser,
Content: string(m),
}
}

type AssistantMessage string

func (m AssistantMessage) ChatMessage() serving.ChatMessage {
return serving.ChatMessage{
Role: serving.ChatMessageRoleAssistant,
Content: string(m),
}
}

type History []message

func (h History) Messages() (out []serving.ChatMessage) {
for _, v := range h {
out = append(out, v.ChatMessage())
}
return
}

func (h History) messageTokens(m message) int {
// this is good enough approximation of message token count
content := m.ChatMessage().Content
return len(strings.Split(content, " "))
}

func (h History) truncated(m message, maxTokens int) message {
// this is good enough approximation of message token count
cm := m.ChatMessage()
tokens := strings.Split(cm.Content, " ")
if len(tokens) < maxTokens {
return m
}
switch m.(type) {
case UserMessage:
return UserMessage(strings.Join(tokens[:maxTokens-100], " "))
case SystemMessage:
return SystemMessage(strings.Join(tokens[:maxTokens-100], " "))
case AssistantMessage:
return AssistantMessage(strings.Join(tokens[:maxTokens-100], " "))
}
panic("cannot truncate message")
}

func (h History) totalTokens() int {
totalTokens := 0
for _, m := range h {
totalTokens += h.messageTokens(m)
}
return totalTokens
}

func (h History) With(m message) History {
maxContextSize := 32768
increment := h.messageTokens(m)
if increment > maxContextSize {
m = h.truncated(m, 32000)
}
return append(h, m)
}

func (h History) Last() string {
return h[len(h)-1].ChatMessage().Content
}

func (h History) Excerpt(n int) string {
var out []string
oneLine := sed.Rule(`\n|\s+`, ` `)
for i, v := range h {
m := v.ChatMessage()
out = append(out, fmt.Sprintf("(%d/%d) %s: %s",
i+1, len(h),
strings.ToUpper(m.Role.String()),
h.onlyNBytes(oneLine.Apply(m.Content), n)))
}
return strings.Join(out, "\n")
}

func (h History) onlyNBytes(j string, numBytes int) string {
diff := len([]byte(j)) - numBytes
if diff > 0 {
return fmt.Sprintf("%s... (%d more bytes)", j[:numBytes], diff)
}
return j
}
Loading