-
Notifications
You must be signed in to change notification settings - Fork 104
Release 7.1.0: complete-external CLI, v8 foundation, #77 fix #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from 19 commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
cf1c0aa
chore(fpf): refresh corpus to 34b4d63 — temporal claim adequacy
m0n0x41d d3ac730
feat(v8): foundation M1 — algebraic types, wire protocol, append-only…
m0n0x41d a3253aa
feat(v8): foundation M2 — HTTP+SSE server + turn driver
m0n0x41d 8e5f704
Add external WorkCommission completion CLI
a74d085
fix(serve): accept artifact_ref as alias for decision_ref in measure/…
m0n0x41d 14a60ab
docs(changelog): record #77 fix under Unreleased
m0n0x41d b7c2ec9
fix(review): address Codex P1/P2 findings on agent driver
m0n0x41d ea68b72
fix(review): honor artifact_ref alias in bindDecisionRef; unique tmp …
m0n0x41d 20fb979
fix(review): order turn.started after StartTurn; treat closed-stream-…
m0n0x41d d79be83
fix(review): tighten permission validation, match cancel to turn id, …
m0n0x41d c6edf0a
fix(review): validate journal appends, dedupe streamed part ids
m0n0x41d d2867a7
fix(review): fail turn on tool/flush errors; journal assistant text/r…
m0n0x41d 5c63eb0
fix(review): send tool args as raw JSON instead of base64
m0n0x41d 3dfa545
fix(review): serialize per-session Append; safe Hub cancel
m0n0x41d 86fa47d
fix(review): reject replayed running turns synchronously
m0n0x41d 024de7f
fix(review): flush deltas on provider error; reject model.set mid-turn
m0n0x41d 162326b
fix(review): map ErrTurnAlreadyRunning to 409 Conflict
m0n0x41d 0b80cf6
fix(review): serialize model.set against turn.submit Load
m0n0x41d 58e6f4b
fix(review): serialize wire-safe SessionPayload on resume
m0n0x41d 17bd63c
fix(review): map permission errors to 400/404 in HTTP transport
m0n0x41d 5bc6248
fix(review): serialize store.Load with concurrent Append writes
m0n0x41d e2b9cf8
fix(review): cancel-aware turn completion and stale-cancel HTTP status
m0n0x41d 4b9a839
Merge pull request #79 from karabelaselias/feature/commission-complet…
m0n0x41d 6cf91b5
docs(changelog): cut [7.1.0] — complete-external CLI + v8 foundation …
m0n0x41d a8d72b8
fix(review): journal canceled permissions and surface failTurn publis…
m0n0x41d 8535cf4
chore(fpf): refresh corpus to ee40821 + add X-SOURCE-RESTORATION pattern
m0n0x41d d5001d6
fix(review): tag ModelChoice and SessionMeta for snake_case JSON wire
m0n0x41d e5a5b25
docs(changelog): expand 7.1.0 v8 hardening list + artifact store meta…
m0n0x41d 247697e
feat(reff): cap R at 0.5 for simulation-only and nonrealizable causal…
m0n0x41d e80ff87
feat(artifact): add C.28 CausalEvidenceSupportBasis and Realizability…
m0n0x41d 0dbbf65
feat(surface): C.28 schemas + soft warning + A.15.4 carrier footer on…
m0n0x41d e3cad19
test(agentdriver): sync fakeTools.calls and drain SSE until turn.comp…
m0n0x41d d45a6e7
test(agentdriver): drain in-flight dispatcher goroutines before store…
m0n0x41d 5d4954e
fix(review): keep journal authoritative and normalise empty tool args
m0n0x41d 2750032
docs(changelog): document post-cut v8 P2 fixes and -race CI test-side…
m0n0x41d File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // Package agentcore is Layer G2 of the v8 agent stack: pure algebraic types | ||
| // for Session/Turn/Part/Permission/SubAgentLink/ModelChoice and the | ||
| // pure transitions that move a Session from one state to the next. | ||
| // | ||
| // All values in this package are immutable. Every transition function takes | ||
| // a Session and returns a NEW Session — no field mutation, no shared slice | ||
| // state. Errors are returned, never thrown. Side effects (disk, network, | ||
| // time) are forbidden here; they live at G0/G1/G3/G5. | ||
| // | ||
| // This package coexists with the legacy [internal/agent] package during the | ||
| // v8 migration. Legacy types remain authoritative for the current coordinator | ||
| // (internal/agentloop). Once M2 cuts the coordinator over to G4, legacy | ||
| // agent.Session/Message will be deprecated. | ||
| // | ||
| // Inexpressible (by design): | ||
| // - Mutating an existing Turn or Part. | ||
| // - Recording a Part without a Turn. | ||
| // - Recording a Turn without a Session. | ||
| // - Resolving a Permission that was never requested. | ||
| // - Completing a Turn that is already complete. | ||
| // - Attaching a SubAgent without naming the parent Turn. | ||
| // | ||
| // Each is rejected by the type system (sealed interfaces, opaque IDs) or by | ||
| // the transition function returning a typed error. | ||
| package agentcore |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package agentcore | ||
|
|
||
| // Typed identifiers prevent cross-domain ID confusion at compile time. | ||
| // SessionID, TurnID, PartID, PermissionID are not interchangeable strings; | ||
| // the compiler rejects passing one where another is expected. | ||
|
|
||
| type SessionID string | ||
|
|
||
| type TurnID string | ||
|
|
||
| type PartID string | ||
|
|
||
| type PermissionID string | ||
|
|
||
| type SubAgentID string | ||
|
|
||
| func (s SessionID) String() string { return string(s) } | ||
| func (t TurnID) String() string { return string(t) } | ||
| func (p PartID) String() string { return string(p) } | ||
| func (p PermissionID) String() string { return string(p) } | ||
| func (s SubAgentID) String() string { return string(s) } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| package agentcore | ||
|
|
||
| // ProviderKind enumerates the LLM provider families haft can speak to. | ||
| // Adding a kind is a deliberate breaking change to G1 — the wire format | ||
| // in Layer P encodes ProviderKind as a string discriminator and consumers | ||
| // will reject unknown values rather than silently ignoring them. | ||
| type ProviderKind string | ||
|
|
||
| const ( | ||
| ProviderOpenAI ProviderKind = "openai" | ||
| ProviderAnthropic ProviderKind = "anthropic" | ||
| // ProviderCodex is the ChatGPT-Sub OAuth path that reuses the OpenAI | ||
| // API surface but carries chatgpt_account_id auth. It is preserved | ||
| // from internal/cli/login.go and remains the only auth flow that | ||
| // requires a device-code exchange. | ||
| ProviderCodex ProviderKind = "codex" | ||
| ) | ||
|
|
||
| // ModelChoice is the immutable triple a Session pins itself to. Switching | ||
| // model mid-session is modeled as the runtime emitting a model.switched | ||
| // event and the next Turn binding to a new ModelChoice; the current Turn | ||
| // keeps the choice it started with. | ||
| type ModelChoice struct { | ||
| Provider ProviderKind | ||
| Model string // provider-native model id (e.g. "gpt-5.4", "claude-sonnet-4-6") | ||
| // CredentialKey identifies which stored credential to use without | ||
| // embedding the secret value here. The G1 provider layer dereferences | ||
| // the key against the credential store at call time. | ||
| CredentialKey string | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,156 @@ | ||
| package agentcore | ||
|
|
||
| import "time" | ||
|
|
||
| // PartKind discriminates Part variants in the wire format. | ||
| // The set is closed — adding a new kind is a breaking change to Layer P. | ||
| type PartKind string | ||
|
|
||
| const ( | ||
| PartKindText PartKind = "text" | ||
| PartKindReasoning PartKind = "reasoning" | ||
| PartKindToolUse PartKind = "tool_use" | ||
| PartKindToolResult PartKind = "tool_result" | ||
| PartKindFileRef PartKind = "file_ref" | ||
| PartKindStepBoundary PartKind = "step_boundary" | ||
| ) | ||
|
|
||
| // Part is a sealed sum type: only the variants in this file implement it. | ||
| // Each Part is an immutable value carrying its kind, ID, and the moment it | ||
| // was attached to its Turn. | ||
| type Part interface { | ||
| Kind() PartKind | ||
| ID() PartID | ||
| CreatedAt() time.Time | ||
| partSeal() | ||
| } | ||
|
|
||
| type partBase struct { | ||
| id PartID | ||
| createdAt time.Time | ||
| } | ||
|
|
||
| func (b partBase) ID() PartID { return b.id } | ||
| func (b partBase) CreatedAt() time.Time { return b.createdAt } | ||
| func (partBase) partSeal() {} | ||
|
|
||
| // TextPart carries assistant or user text. Append-only — deltas materialize | ||
| // as additional TextParts; the runtime never mutates an existing TextPart's | ||
| // Text field. Compaction logic lives at G4 and produces NEW Parts. | ||
| type TextPart struct { | ||
| partBase | ||
| Text string | ||
| } | ||
|
|
||
| func (TextPart) Kind() PartKind { return PartKindText } | ||
|
|
||
| // ReasoningPart carries hidden chain-of-thought text streamed from providers | ||
| // that surface it (e.g. OpenAI o1, Anthropic thinking blocks). Rendered | ||
| // dimly in the TUI; not folded into LLM input by default. | ||
| type ReasoningPart struct { | ||
| partBase | ||
| Text string | ||
| } | ||
|
|
||
| func (ReasoningPart) Kind() PartKind { return PartKindReasoning } | ||
|
|
||
| // ToolUsePart marks the start of a tool invocation. Args is the raw | ||
| // JSON-encoded argument blob the LLM produced. ToolCallID is the | ||
| // provider-assigned identifier the matching ToolResultPart will reference. | ||
| type ToolUsePart struct { | ||
| partBase | ||
| ToolCallID string | ||
| ToolName string | ||
| Args []byte | ||
| } | ||
|
|
||
| func (ToolUsePart) Kind() PartKind { return PartKindToolUse } | ||
|
|
||
| // ToolResultPart carries the typed outcome of a tool invocation. IsError is | ||
| // distinct from a non-zero exit code — it signals that the tool layer | ||
| // itself failed (timeout, cancelled, dispatch error) and the LLM should | ||
| // reason about the failure. | ||
| type ToolResultPart struct { | ||
| partBase | ||
| ToolCallID string | ||
| ToolName string | ||
| Content string | ||
| IsError bool | ||
| } | ||
|
|
||
| func (ToolResultPart) Kind() PartKind { return PartKindToolResult } | ||
|
|
||
| // FileRefPart records that a tool attached a file to the Turn. Path is | ||
| // project-relative when possible. The TUI uses this to render an inline | ||
| // chip and offers a viewer command. | ||
| type FileRefPart struct { | ||
| partBase | ||
| Path string | ||
| MIMEType string | ||
| Bytes int64 | ||
| } | ||
|
|
||
| func (FileRefPart) Kind() PartKind { return PartKindFileRef } | ||
|
|
||
| // StepBoundaryPart marks a logical step inside a Turn — used by providers | ||
| // that batch tool calls into agentic "steps". Lets the TUI fold sections. | ||
| // Carries no payload beyond its own identity and timestamp. | ||
| type StepBoundaryPart struct { | ||
| partBase | ||
| Label string | ||
| } | ||
|
|
||
| func (StepBoundaryPart) Kind() PartKind { return PartKindStepBoundary } | ||
|
|
||
| // NewTextPart, NewReasoningPart, ... are the only constructors. They stamp | ||
| // CreatedAt at call time. Tests override via the now closure passed to | ||
| // transition functions; production calls use time.Now. | ||
|
|
||
| func newPartBase(id PartID, now time.Time) partBase { | ||
| return partBase{id: id, createdAt: now} | ||
| } | ||
|
|
||
| func NewTextPart(id PartID, now time.Time, text string) TextPart { | ||
| return TextPart{partBase: newPartBase(id, now), Text: text} | ||
| } | ||
|
|
||
| func NewReasoningPart(id PartID, now time.Time, text string) ReasoningPart { | ||
| return ReasoningPart{partBase: newPartBase(id, now), Text: text} | ||
| } | ||
|
|
||
| func NewToolUsePart(id PartID, now time.Time, callID, name string, args []byte) ToolUsePart { | ||
| cloned := make([]byte, len(args)) | ||
| copy(cloned, args) | ||
| return ToolUsePart{ | ||
| partBase: newPartBase(id, now), | ||
| ToolCallID: callID, | ||
| ToolName: name, | ||
| Args: cloned, | ||
| } | ||
| } | ||
|
|
||
| func NewToolResultPart(id PartID, now time.Time, callID, name, content string, isError bool) ToolResultPart { | ||
| return ToolResultPart{ | ||
| partBase: newPartBase(id, now), | ||
| ToolCallID: callID, | ||
| ToolName: name, | ||
| Content: content, | ||
| IsError: isError, | ||
| } | ||
| } | ||
|
|
||
| func NewFileRefPart(id PartID, now time.Time, path, mime string, bytes int64) FileRefPart { | ||
| return FileRefPart{ | ||
| partBase: newPartBase(id, now), | ||
| Path: path, | ||
| MIMEType: mime, | ||
| Bytes: bytes, | ||
| } | ||
| } | ||
|
|
||
| func NewStepBoundaryPart(id PartID, now time.Time, label string) StepBoundaryPart { | ||
| return StepBoundaryPart{ | ||
| partBase: newPartBase(id, now), | ||
| Label: label, | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| package agentcore | ||
|
|
||
| import "time" | ||
|
|
||
| // PermissionDecision is the operator's response to a permission request. | ||
| // Resolution is terminal — once set, it cannot change. Re-asking for the | ||
| // same operation creates a NEW Permission. | ||
| type PermissionDecision string | ||
|
|
||
| const ( | ||
| PermissionPending PermissionDecision = "pending" | ||
| PermissionApproved PermissionDecision = "approved" | ||
| PermissionDenied PermissionDecision = "denied" | ||
| ) | ||
|
|
||
| // Permission is a request to run a specific tool invocation, surfaced to | ||
| // the operator and resolved by their decision. The Permission record | ||
| // participates in the Session graph just like any other entity: it is | ||
| // created, eventually resolved, and never mutated after resolution. | ||
| type Permission struct { | ||
| ID PermissionID | ||
| TurnID TurnID | ||
| ToolCallID string | ||
| ToolName string | ||
| Args []byte | ||
| Decision PermissionDecision | ||
| Reason string // operator-provided justification on deny; optional on approve | ||
| RequestedAt time.Time | ||
| ResolvedAt time.Time // zero until Decision != Pending | ||
| } | ||
|
|
||
| // IsResolved reports whether the operator has decided. | ||
| func (p Permission) IsResolved() bool { | ||
| return p.Decision != PermissionPending | ||
| } | ||
|
|
||
| // withResolution returns a copy of the Permission marked with the given | ||
| // decision at the given time. The receiver is untouched. | ||
| func (p Permission) withResolution(d PermissionDecision, reason string, now time.Time) Permission { | ||
| p.Decision = d | ||
| p.Reason = reason | ||
| p.ResolvedAt = now | ||
| return p | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.