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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ jwtwrapper/__pycache__/
# .vscode/

.dreams
.debates
.vscode
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ go build ./
Start the local server (default: port 8080).

```bash
./ProjectIolite
./ProjectIolite -recursions=3
```

4. INITIATE A 'THINK' REQUEST
Expand Down
81 changes: 54 additions & 27 deletions brain/decision.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package brain

import (
"context"
"errors"
"log"
"slices"
"time"
)
Expand All @@ -27,25 +29,47 @@ func (e *BaseDecision) Compose(sv SignVerifier, d Decision) error {
for k := range otherCoT {
e.ChainOfThoughts[k] = append(e.ChainOfThoughts[k], otherCoT[k]...)
}
other := d.Prompts()
for k := range other {
if len(other[k]) > 1 {
e.AllPrompts[k] = append(e.AllPrompts[k], other[k][1:]...) // first is *always* the genesis prompt
log.Printf("merging prompts\n")
e.AllPrompts = mergeSignedSlices(e.AllPrompts, d.Prompts())
log.Printf("merging text\n")
e.AllTexts = mergeSignedSlices(e.AllTexts, d.Texts())
log.Printf("merging tool requests\n")
e.AllToolRequests = mergeSignedSlices(e.AllToolRequests, d.ToolRequests())
log.Printf("merging tool responses\n")
e.AllToolResponses = mergeSignedSlices(e.AllToolResponses, d.ToolResponses())
e.Audits = append(e.Audits, d.GetAudits()...)
log.Printf("test verify: %s", e.Verify(sv))
return nil
}

// Internal helper to merge slices based on signature parity
func mergeSignedSlices(existing, incoming map[string][]Signed) map[string][]Signed {
for k, exBlocks := range existing {
for _, b := range exBlocks {
log.Printf("%s existing: %#v\n", k, b)
}
}
other = d.Texts()
for k := range other {
e.AllTexts[k] = append(e.AllTexts[k], other[k]...)
}
other = d.ToolRequests()
for k := range other {
e.AllToolRequests[k] = append(e.AllToolRequests[k], other[k]...)
for k, inBlocks := range incoming {
for _, b := range inBlocks {
log.Printf("%s incoming: %#v\n", k, b)
}
}
other = d.ToolResponses()
for k := range other {
e.AllToolResponses[k] = append(e.AllToolResponses[k], other[k]...)
for k, inBlocks := range incoming {
// Create a map of existing signatures for this namespace
seen := make(map[string]bool)
for _, b := range existing[k] {
seen[b.Signature] = true
}

for _, b := range inBlocks {
if !seen[b.Signature] {
existing[k] = append(existing[k], b)
} else {
log.Printf("got a block we've already seen?? %#v", b)
}
}
}
return e.Verify(sv)
return existing
}

func (e *BaseDecision) IsError() error {
Expand All @@ -57,6 +81,9 @@ func (e *BaseDecision) SetError(err error) {
}

func NewBaseDecision(source string, init Response, sv SignVerifier) (*BaseDecision, error) {
if source == "mock" {
return nil, errors.New("no mock models allowed")
}
allPrompts := map[string][]Signed{}
genesis := init.GenesisPrompt()
if genesis != nil {
Expand Down Expand Up @@ -86,7 +113,7 @@ func NewBaseDecision(source string, init Response, sv SignVerifier) (*BaseDecisi

func (d *BaseDecision) Sign(sv SignVerifier) error {
for k := range d.ChainOfThoughts {
if k == d.Source {
if k == d.Source || d.Source == "mock" {
for i := range d.ChainOfThoughts[k] {
for j := range d.ChainOfThoughts[k][i] {
if d.ChainOfThoughts[k][i][j].Signature == "" {
Expand All @@ -108,7 +135,7 @@ func (d *BaseDecision) Sign(sv SignVerifier) error {
}
}
for k := range d.AllPrompts {
if k == d.Source {
if k == d.Source || d.Source == "mock" {
for i := range d.AllPrompts[k] {
if d.AllPrompts[k][i].Signature == "" {
err := d.AllPrompts[k][i].Sign(sv)
Expand All @@ -126,7 +153,7 @@ func (d *BaseDecision) Sign(sv SignVerifier) error {
}
}
for k := range d.AllTexts {
if k == d.Source {
if k == d.Source || d.Source == "mock" {
for i := range d.AllTexts[k] {
if d.AllTexts[k][i].Signature == "" {
err := d.AllTexts[k][i].Sign(sv)
Expand All @@ -144,7 +171,7 @@ func (d *BaseDecision) Sign(sv SignVerifier) error {
}
}
for k := range d.AllToolRequests {
if k == d.Source {
if k == d.Source || d.Source == "mock" {
for i := range d.AllToolRequests[k] {
if d.AllToolRequests[k][i].Signature == "" {
err := d.AllToolRequests[k][i].Sign(sv)
Expand All @@ -162,7 +189,7 @@ func (d *BaseDecision) Sign(sv SignVerifier) error {
}
}
for k := range d.AllToolResponses {
if k == d.Source {
if k == d.Source || d.Source == "mock" {
for i := range d.AllToolResponses[k] {
if d.AllToolResponses[k][i].Signature == "" {
err := d.AllToolResponses[k][i].Sign(sv)
Expand All @@ -182,33 +209,33 @@ func (d *BaseDecision) Sign(sv SignVerifier) error {
return nil
}

func (d *BaseDecision) Blocks() []Signed {
bs := []Signed{}
func (d *BaseDecision) Blocks() []*Signed {
bs := []*Signed{}
for k := range d.ChainOfThoughts {
for i := range d.ChainOfThoughts[k] {
for j := range d.ChainOfThoughts[k][i] {
bs = append(bs, d.ChainOfThoughts[k][i][j])
bs = append(bs, &d.ChainOfThoughts[k][i][j])
}
}
}
for k := range d.AllPrompts {
for i := range d.AllPrompts[k] {
bs = append(bs, d.AllPrompts[k][i])
bs = append(bs, &d.AllPrompts[k][i])
}
}
for k := range d.AllTexts {
for i := range d.AllTexts[k] {
bs = append(bs, d.AllTexts[k][i])
bs = append(bs, &d.AllTexts[k][i])
}
}
for k := range d.AllToolRequests {
for i := range d.AllToolRequests[k] {
bs = append(bs, d.AllToolRequests[k][i])
bs = append(bs, &d.AllToolRequests[k][i])
}
}
for k := range d.AllToolResponses {
for i := range d.AllToolResponses[k] {
bs = append(bs, d.AllToolResponses[k][i])
bs = append(bs, &d.AllToolResponses[k][i])
}
}
return bs
Expand Down
81 changes: 70 additions & 11 deletions brain/decision_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1056,13 +1056,43 @@ func walkBraid(dec *BaseDecision, fn func(Signed)) {

func TestCompose(t *testing.T) {
t.Run("Compose will combine decisions together", func(t *testing.T) {
sigs := map[string]struct{}{
"gp": {},
"ctool": {},
"ctr": {},
"gt": {},
"ct": {},
"gc1": {},
"cc1": {},
"gc2": {},
"cc2": {},
"next_gp": {},
"next_ct": {},
"next_ctool": {},
"next_ctr": {},
"next_gt": {},
"next_gc1": {},
"next_gc2": {},
"next_cc1": {},
"next_cc2": {},
"next_gp2": {},
"next_ct2": {},
"next_ctool2": {},
"next_ctr2": {},
"next_gt2": {},
"next_gc3": {},
"next_gc4": {},
"next_cc3": {},
"next_cc4": {},
}
ds := Decisions{
&BaseDecision{
Source: "mock",
AllPrompts: map[string][]Signed{
"gemini": {{Data: "gp"}},
},
AllToolRequests: map[string][]Signed{
"claude": {{Data: "ct"}},
"claude": {{Data: "ctool"}},
},
AllToolResponses: map[string][]Signed{
"claude": {{Data: "ctr"}},
Expand All @@ -1077,11 +1107,12 @@ func TestCompose(t *testing.T) {
},
},
&BaseDecision{
Source: "mock",
AllPrompts: map[string][]Signed{
"gemini": {{Data: "gp"}, {Data: "next_gp"}},
},
AllToolRequests: map[string][]Signed{
"claude": {{Data: "next_ct"}},
"claude": {{Data: "next_ctool"}},
},
AllToolResponses: map[string][]Signed{
"claude": {{Data: "next_ctr"}},
Expand All @@ -1095,23 +1126,51 @@ func TestCompose(t *testing.T) {
"claude": {{{Data: "next_cc1"}, {Data: "next_cc2"}}},
},
},
&BaseDecision{
Source: "mock",
AllPrompts: map[string][]Signed{
"gemini": {{Data: "gp"}, {Data: "next_gp"}, {Data: "next_gp2"}},
},
AllToolRequests: map[string][]Signed{
"claude": {{Data: "next_ctool2"}},
},
AllToolResponses: map[string][]Signed{
"claude": {{Data: "next_ctr2"}},
},
AllTexts: map[string][]Signed{
"gemini": {{Data: "next_gt2"}},
"claude": {{Data: "next_ct2"}},
},
ChainOfThoughts: map[string][][]Signed{
"gemini": {{{Data: "next_gc3"}, {Data: "next_gc4"}}},
"claude": {{{Data: "next_cc3"}, {Data: "next_cc4"}}},
},
},
}
sv := new(MockSignVerifier)
sv.On("Sign", mock.Anything).Return("valid", nil).Maybe()
sv.On("Verify", "", "sig1").Return(nil).Once()
for k := range sigs {
sv.On("Sign", b64(k)).Return(k+"sig", nil).Maybe()
sv.On("Sign", b64(k)+"sig").Return(k+"sig", nil).Maybe()
sv.On("Verify", b64(k), k+"sig").Return(nil).Maybe()
}
assert.NoError(t, ds[0].Sign(sv))
assert.NoError(t, ds[1].Sign(sv))
assert.NoError(t, ds[2].Sign(sv))
folded := ds.Fold(sv)
// TODO: this is kinda lazy but gets the parity right
assert.Len(t, folded.Prompts()["gemini"], 2)
assert.Len(t, folded.Prompts()["gemini"], 3)
assert.Len(t, folded.Prompts()["claude"], 0)
assert.Len(t, folded.ToolRequests()["claude"], 2)
assert.Len(t, folded.ToolResponses()["claude"], 2)
assert.Len(t, folded.Texts()["claude"], 2)
assert.Len(t, folded.Texts()["gemini"], 2)
assert.Len(t, folded.Cots()["claude"], 2)
assert.Len(t, folded.Cots()["gemini"], 2)
assert.Len(t, folded.ToolRequests()["claude"], 3)
assert.Len(t, folded.ToolResponses()["claude"], 3)
assert.Len(t, folded.Texts()["claude"], 3)
assert.Len(t, folded.Texts()["gemini"], 3)
assert.Len(t, folded.Cots()["claude"], 3)
assert.Len(t, folded.Cots()["gemini"], 3)
assert.Len(t, folded.Cots()["claude"][0], 2)
assert.Len(t, folded.Cots()["gemini"][0], 2)
assert.Len(t, folded.Cots()["claude"][1], 2)
assert.Len(t, folded.Cots()["gemini"][1], 2)
assert.Len(t, folded.Cots()["claude"][2], 2)
assert.Len(t, folded.Cots()["gemini"][2], 2)
})
}
4 changes: 2 additions & 2 deletions brain/dream.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ func (sh *SignedHydration) Verify(sv SignVerifier) error {
return sv.Verify(sh.Signed.Data+sh.Signed.PrevSignature, sh.Signed.Signature)
}

func (d *SignedHydration) Blocks() []Signed {
return []Signed{d.Signed}
func (d *SignedHydration) Blocks() []*Signed {
return []*Signed{&d.Signed}
}

func GenerateDreamPrompt(ctx context.Context, spec *openapi3.T, sv SignVerifier) (Signed, error) {
Expand Down
8 changes: 6 additions & 2 deletions brain/errords.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type ErrorResponse struct {
E error
}

func (ErrorResponse) CoT(_ SignVerifier) []Signed {
func (ErrorResponse) CoT(_ SignVerifier, _ ...bool) []Signed {
return nil
}

Expand All @@ -20,7 +20,11 @@ func (e *ErrorResponse) Text() *Signed {
return &Signed{Data: e.E.Error()}
}

func (e *ErrorResponse) Prompt() Signed {
func (e *ErrorResponse) Thought(...bool) Signed {
return *e.Text()
}

func (e *ErrorResponse) Prompt(...bool) Signed {
return Signed{Data: e.E.Error()}
}

Expand Down
8 changes: 6 additions & 2 deletions brain/mockresponse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
// MockResponse is now exported for use in gemini/claude tests
type MockResponse struct{ mock.Mock }

func (m *MockResponse) CoT(sv SignVerifier) []Signed {
func (m *MockResponse) CoT(sv SignVerifier, _ ...bool) []Signed {
args := m.Called(sv)
return args.Get(0).([]Signed)
}
Expand All @@ -21,7 +21,11 @@ func (m *MockResponse) Text() *Signed {
return args.Get(0).(*Signed)
}

func (m *MockResponse) Prompt() Signed {
func (m *MockResponse) Thought(...bool) Signed {
return *m.Text()
}

func (m *MockResponse) Prompt(...bool) Signed {
args := m.Called()
return args.Get(0).(Signed)
}
Expand Down
2 changes: 1 addition & 1 deletion brain/mockthinker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ func (*MockThinker) Wake(_ context.Context, _ SignVerifier, _ SignedHydration) e
}

func (*MockThinker) Model() string {
return "mock"
return "testmock"
}
21 changes: 18 additions & 3 deletions brain/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,30 @@ type BaseResponse struct {
e error
}

func NewBaseResponse(source string, prompt Signed, genesis ...Signed) *BaseResponse {
return &BaseResponse{
func NewBaseResponse(sv SignVerifier, source string, prompt Signed, genesis ...Signed) (*BaseResponse, error) {
r := &BaseResponse{
source: source,
prompt: prompt,
genesis: genesis,
}
if len(r.genesis) > 0 {
// Re-sign the prompt, this will be re-keyed to the Genesis
r.prompt.PrevSignature = r.GenesisPrompt().Signature
r.prompt.Signature = ""
err := r.prompt.Sign(sv)
if err != nil {
return nil, err
}
}
return r, nil
}

func (r *BaseResponse) Prompt() Signed {
func (r *BaseResponse) Prompt(quiet ...bool) Signed {
if len(quiet) > 0 && quiet[0] {
p := r.prompt
p.Data64 = ""
return p
}
return r.prompt
}

Expand Down
Loading
Loading