Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
c2a4e40
chore: ignore local RSS checkpoint run state
Aug 5, 2026
9838ba2
feat(sdk): extract a standalone session runtime and lazy-load notific…
Aug 5, 2026
1fafeb9
feat(runtime-mcp): pool MCP connections behind leases and share them …
Aug 5, 2026
9312d9e
perf(natives): load the native addon lazily from every importer
Aug 5, 2026
8d150f8
feat(ai): add a /core entrypoint that excludes provider construction
Aug 5, 2026
7563a9d
refactor(coding-agent): import the AI core surface instead of the pac…
Aug 5, 2026
307851a
feat(agent): do no span work when telemetry spans are disabled
Aug 5, 2026
6661afd
feat(gjc-plugins): cut over to registry v2 with a single execution au…
Aug 5, 2026
f80ef73
fix(computer): restore batch failure shape, timeouts and coordinate v…
Aug 5, 2026
91ff63f
refactor(tools): split tool descriptors from implementations
Aug 5, 2026
5ce13f8
refactor(session): defer session artifact and history storage work
Aug 5, 2026
74db8fb
refactor(coding-agent): keep MCP, skills and eval work off the startu…
Aug 5, 2026
ced1d9c
build: gate the AI core boundary and block the legacy plugin loader s…
Aug 5, 2026
0d2c351
test(harness): add RSS checkpoint and module-trace verification gates
Aug 5, 2026
624526a
fix(sdk): keep session.delete idempotent without cleanup evidence
Aug 6, 2026
087d11e
test(tools): move the catalog reproducibility test out of src
Aug 6, 2026
24d4dba
chore(guard): refresh the daemon generation manifest digests
Aug 6, 2026
5764af9
style: format the perf work and drop its dead leftovers
Aug 6, 2026
7fa3575
fix(sdk): keep the bus native load off the startup await path
Aug 6, 2026
4aae6ab
fix(tools): keep deferred descriptors honest about conditional tools
Aug 6, 2026
0e074fa
fix(ci): enforce team continuation ordering in the canonicalization gate
Aug 6, 2026
84f2854
docs: record the startup memory changes in package changelogs
Aug 6, 2026
3909193
test(ci): make startup harness and descriptor gates self-contained
Aug 6, 2026
3ec3487
fix(runtime): preserve lazy feature behavior at activation boundaries
Aug 6, 2026
f55066c
fix(session): harden lazy managed-storage authority
Aug 6, 2026
69700ec
fix(daemon): advance chat generations for lazy authority
Aug 6, 2026
1ccb5ab
fix(session): reacquire exact authority for stale lock descriptors
Aug 6, 2026
13b45ad
test(session): retry transient large-tree cleanup faults
Aug 6, 2026
436b708
fix(session): fail closed when tool-output eviction artifacts are una…
gaebal-gajae Aug 6, 2026
b111555
fix(ci): reconcile daemon authority after live-base rebase
Aug 7, 2026
9f3eef7
fix(daemon): resolve gen-56 conflict after #3974 rebase
gaebal-gajae Aug 7, 2026
a8851ab
fix(ai): correct rebased core compat type import
Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ packages/ai/test/.temp-images/
.gjc/rlm/
.gjc/state/
.gjc/_session-*/
.gjc/rss-checkpoints/
.gjc/metrics.json
.pi_config/
.opencode/
Expand Down
19 changes: 19 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,25 @@
}
}
},
"overrides": [
{
"includes": ["packages/coding-agent/src/**"],
"linter": {
"rules": {
"style": {
"noRestrictedImports": {
"level": "error",
"options": {
"paths": {
"@gajae-code/ai": "Import from @gajae-code/ai/core instead."
}
}
}
}
}
}
}
],
"formatter": {
"enabled": true,
"indentStyle": "tab",
Expand Down
3 changes: 3 additions & 0 deletions packages/agent/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
### Fixed

- An aborted run whose tool ignores its `AbortSignal` now terminates on its own (#3894). `Promise.allSettled` waited on the unresolved call forever, so the turn only ended when the session's force-abort budget expired; the loop now emits a synthetic aborted result for the outstanding calls and `waitForIdle` settles immediately. Session dispose consequently reaches idle through the cooperative path instead of force-invalidating the run.
### Changed

- Telemetry configured with `spans: false` now skips span and attribute construction while preserving usage and cost hooks.

## [0.12.12] - 2026-08-05

Expand Down
12 changes: 10 additions & 2 deletions packages/agent/src/agent-loop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1521,11 +1521,18 @@ async function runLoopBody(
awaitEventDrain: (invocationSignal: AbortSignal) =>
stream.waitForConsumerDrain(AbortSignal.any([loopSignal, invocationSignal])),
};
const maintenanceOutcome = await config.maintainContext(currentContext, lifecycle);
const maintenanceResult = await config.maintainContext(currentContext, lifecycle);
const maintenance =
typeof maintenanceResult === "string" ? { outcome: maintenanceResult } : maintenanceResult;
// A callback can settle after its loop has been cancelled. Never let a
// stale "not-needed" fall through to streamAssistantResponse, which
// invokes the provider before it observes the aborted signal.
const outcome = loopSignal.aborted ? "aborted" : maintenanceOutcome;
const outcome = loopSignal.aborted ? "aborted" : maintenance.outcome;
if (maintenance.releaseCurrentContext) {
currentContext.messages.length = 0;
newMessages.length = 0;
convertedContextCache.delete(config);
}

if (outcome !== "not-needed") {
publishAgentEnd(
Expand Down Expand Up @@ -2440,6 +2447,7 @@ async function streamAssistantResponse(
});
} catch (err) {
failChatSpan(telemetry, chatSpan, {
stepNumber: chatStepNumber,
errorObject: err,
responseHeaders: capturedHeaders,
baseUrl: config.model.baseUrl,
Expand Down
9 changes: 8 additions & 1 deletion packages/agent/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -980,7 +980,14 @@ export class Agent {
this.#contextRevision++;
}

replaceMessages(ms: AgentMessage[]) {
replaceMessages(
ms: AgentMessage[],
options?: { historyRewrite?: { reason: string; preserveSeededPrefix?: boolean } },
) {
const rewrite = options?.historyRewrite;
if (rewrite && this.#appendOnlyContext) {
this.#appendOnlyContext.releaseAfterHistoryRewrite({ preserveSeededPrefix: rewrite.preserveSeededPrefix });
}
this.#state.messages = ms.slice();
this.#contextRevision++;
}
Expand Down
15 changes: 13 additions & 2 deletions packages/agent/src/append-only-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ export class AppendOnlyContextManager {

const newMsgs = messagesToSync.slice(this.#lastSyncCount);
for (const msg of newMsgs) {
this.log.append(msg);
this.log.append(cloneJson(msg));
}

this.#lastSyncCount = messagesToSync.length;
Expand Down Expand Up @@ -341,6 +341,17 @@ export class AppendOnlyContextManager {
this.log.replaceTail(message);
}

/** Release provider-normalized retainers as one history-rewrite transaction. */
releaseAfterHistoryRewrite(options: { preserveSeededPrefix?: boolean } = {}): void {
const seeded = options.preserveSeededPrefix === true ? this.#seededPrefixCount : 0;
const prefix = seeded > 0 ? this.log.entries().slice(0, seeded) : [];
this.log.clear();
if (prefix.length > 0) this.log.extend(prefix);
this.#lastSyncCount = prefix.length;
this.#seededPrefixCount = prefix.length;
this.#syncedHashes = this.#hashRange(prefix, 0, prefix.length);
this.invalidate();
}
invalidate(): void {
this.prefix.invalidate();
}
Expand Down Expand Up @@ -384,7 +395,7 @@ export class AppendOnlyContextManager {
/** F9: reset the log to a new provider-visible baseline after seeded compaction/rebase. */
#rebaseToBaseline(messages: readonly unknown[], seededPrefixCount = 0): void {
this.log.clear();
this.log.extend([...messages]);
this.log.extend(messages.map(message => cloneJson(message)));
this.#lastSyncCount = messages.length;
this.#seededPrefixCount = seededPrefixCount;
this.#syncedHashes = this.#hashRange(messages, 0, messages.length);
Expand Down
Loading
Loading