@gajae-code/agent-core 0.11.11 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/types/agent.d.ts +8 -1
- package/dist/types/compaction/openai.d.ts +2 -0
- package/dist/types/compaction/pruning.d.ts +29 -3
- package/dist/types/index.d.ts +1 -0
- package/dist/types/run-resource-ledger.d.ts +2 -0
- package/dist/types/types.d.ts +34 -0
- package/package.json +4 -4
- package/src/agent-loop.ts +128 -30
- package/src/agent.ts +40 -3
- package/src/compaction/openai.ts +8 -2
- package/src/compaction/pruning.ts +325 -131
- package/src/index.ts +1 -0
- package/src/run-resource-ledger.ts +209 -0
- package/src/types.ts +30 -0
package/src/agent.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { agentLoop, agentLoopContinue } from "./agent-loop";
|
|
|
25
25
|
import type { AppendOnlyContextManager } from "./append-only-context";
|
|
26
26
|
import type { HarmonyAuditEvent } from "./harmony-leak";
|
|
27
27
|
import { assertImagePlaceholdersHavePayload } from "./image-placeholder-guard";
|
|
28
|
+
import { createRunResourceLedger } from "./run-resource-ledger";
|
|
28
29
|
import type {
|
|
29
30
|
AgentContext,
|
|
30
31
|
AgentEvent,
|
|
@@ -38,6 +39,7 @@ import type {
|
|
|
38
39
|
ManagedAttemptDecision,
|
|
39
40
|
ManagedAttemptOutcome,
|
|
40
41
|
ManagedLogicalRunId,
|
|
42
|
+
RunResourceLedger,
|
|
41
43
|
RunTerminalRequest,
|
|
42
44
|
StreamFn,
|
|
43
45
|
ToolCallContext,
|
|
@@ -235,6 +237,8 @@ export interface AgentOptions {
|
|
|
235
237
|
requestMaxRetries?: number;
|
|
236
238
|
/** Provider stream replay retry budget. Counts retries, not the initial attempt. */
|
|
237
239
|
streamMaxRetries?: number;
|
|
240
|
+
/** Explicit first-event stream watchdog override in milliseconds. Set to 0 to disable. */
|
|
241
|
+
streamFirstEventTimeoutMs?: number;
|
|
238
242
|
|
|
239
243
|
/**
|
|
240
244
|
* Provides tool execution context, resolved per tool call.
|
|
@@ -354,6 +358,7 @@ export class Agent {
|
|
|
354
358
|
#maxRetryDelayMs?: number;
|
|
355
359
|
#requestMaxRetries?: number;
|
|
356
360
|
#streamMaxRetries?: number;
|
|
361
|
+
#streamFirstEventTimeoutMs?: number;
|
|
357
362
|
#getToolContext?: (toolCall?: ToolCallContext) => AgentToolContext | undefined;
|
|
358
363
|
#cursorExecHandlers?: CursorExecHandlers;
|
|
359
364
|
#cursorOnToolResult?: CursorToolResultHandler;
|
|
@@ -361,6 +366,7 @@ export class Agent {
|
|
|
361
366
|
#resolveRunningPrompt?: () => void;
|
|
362
367
|
#runSequence = 0;
|
|
363
368
|
#activeRunId?: number;
|
|
369
|
+
#activeResourceRunId?: string;
|
|
364
370
|
#continuationGeneration = 0;
|
|
365
371
|
#activeFallbackManaged = false;
|
|
366
372
|
#kimiApiFormat?: "openai" | "anthropic";
|
|
@@ -388,6 +394,7 @@ export class Agent {
|
|
|
388
394
|
#cursorToolResultBuffer: CursorToolResultEntry[] = [];
|
|
389
395
|
#terminalizedLogicalRunIds = new Set<ManagedLogicalRunId>();
|
|
390
396
|
#managedLogicalRunOwner?: ManagedLogicalRunId;
|
|
397
|
+
readonly resourceLedger: RunResourceLedger = createRunResourceLedger();
|
|
391
398
|
|
|
392
399
|
streamFn: StreamFn;
|
|
393
400
|
getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
|
|
@@ -426,6 +433,7 @@ export class Agent {
|
|
|
426
433
|
this.#maxRetryDelayMs = opts.maxRetryDelayMs;
|
|
427
434
|
this.#requestMaxRetries = opts.requestMaxRetries;
|
|
428
435
|
this.#streamMaxRetries = opts.streamMaxRetries;
|
|
436
|
+
this.#streamFirstEventTimeoutMs = opts.streamFirstEventTimeoutMs;
|
|
429
437
|
this.getApiKey = opts.getApiKey;
|
|
430
438
|
this.getAuthCredentialType = opts.getAuthCredentialType;
|
|
431
439
|
this.#onPayload = opts.onPayload;
|
|
@@ -671,6 +679,14 @@ export class Agent {
|
|
|
671
679
|
this.#streamMaxRetries = value;
|
|
672
680
|
}
|
|
673
681
|
|
|
682
|
+
get streamFirstEventTimeoutMs(): number | undefined {
|
|
683
|
+
return this.#streamFirstEventTimeoutMs;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
set streamFirstEventTimeoutMs(value: number | undefined) {
|
|
687
|
+
this.#streamFirstEventTimeoutMs = value;
|
|
688
|
+
}
|
|
689
|
+
|
|
674
690
|
get state(): AgentState {
|
|
675
691
|
return this.#state;
|
|
676
692
|
}
|
|
@@ -1152,12 +1168,14 @@ export class Agent {
|
|
|
1152
1168
|
this.#state.pendingToolCalls = new Set<string>();
|
|
1153
1169
|
this.#abortController = undefined;
|
|
1154
1170
|
this.#cursorToolResultBuffer = [];
|
|
1171
|
+
this.resourceLedger.quarantine(this.#activeResourceRunId ?? String(managedLogicalRunId ?? runId));
|
|
1155
1172
|
this.#managedLogicalRunOwner = undefined;
|
|
1156
1173
|
|
|
1157
1174
|
const resolve = this.#resolveRunningPrompt;
|
|
1158
1175
|
this.#runningPrompt = undefined;
|
|
1159
1176
|
this.#resolveRunningPrompt = undefined;
|
|
1160
1177
|
this.#activeRunId = undefined;
|
|
1178
|
+
this.#activeResourceRunId = undefined;
|
|
1161
1179
|
resolve?.();
|
|
1162
1180
|
if (this.#activeFallbackManaged) {
|
|
1163
1181
|
this.requestRunTerminal(managedLogicalRunId ?? runId, { stopReason: "cancelled" });
|
|
@@ -1175,6 +1193,10 @@ export class Agent {
|
|
|
1175
1193
|
get activeRunId(): number | undefined {
|
|
1176
1194
|
return this.#activeRunId;
|
|
1177
1195
|
}
|
|
1196
|
+
/** Stable resource ownership identifier for the active prompt run. */
|
|
1197
|
+
get activeResourceRunId(): string | undefined {
|
|
1198
|
+
return this.#activeResourceRunId;
|
|
1199
|
+
}
|
|
1178
1200
|
|
|
1179
1201
|
/**
|
|
1180
1202
|
* Stable identifier for the active managed logical run, shared by every retry
|
|
@@ -1196,6 +1218,9 @@ export class Agent {
|
|
|
1196
1218
|
*/
|
|
1197
1219
|
requestRunTerminal(logicalRunId: ManagedLogicalRunId, request: RunTerminalRequest): boolean {
|
|
1198
1220
|
if (this.#terminalizedLogicalRunIds.has(logicalRunId)) return false;
|
|
1221
|
+
if (this.#managedLogicalRunOwner === logicalRunId) {
|
|
1222
|
+
this.#managedLogicalRunOwner = undefined;
|
|
1223
|
+
}
|
|
1199
1224
|
this.#finalizeRun(
|
|
1200
1225
|
logicalRunId,
|
|
1201
1226
|
{
|
|
@@ -1339,11 +1364,13 @@ export class Agent {
|
|
|
1339
1364
|
this.#state.isStreaming = true;
|
|
1340
1365
|
this.#state.streamMessage = null;
|
|
1341
1366
|
this.#state.error = undefined;
|
|
1342
|
-
options?.onRunAccepted?.();
|
|
1343
1367
|
|
|
1344
1368
|
const fallbackManaged = options?.fallbackManaged === true;
|
|
1345
1369
|
const managedLogicalRunOwner = fallbackManaged ? (this.#managedLogicalRunOwner ?? runId) : undefined;
|
|
1346
1370
|
const startsManagedLogicalRun = fallbackManaged && this.#managedLogicalRunOwner === undefined;
|
|
1371
|
+
this.#activeResourceRunId = String(managedLogicalRunOwner ?? runId);
|
|
1372
|
+
this.resourceLedger.open(this.#activeResourceRunId);
|
|
1373
|
+
options?.onRunAccepted?.();
|
|
1347
1374
|
if (startsManagedLogicalRun) {
|
|
1348
1375
|
this.#managedLogicalRunOwner = managedLogicalRunOwner;
|
|
1349
1376
|
this.#emit({ type: "agent_start" });
|
|
@@ -1355,6 +1382,7 @@ export class Agent {
|
|
|
1355
1382
|
this.#state.isStreaming = false;
|
|
1356
1383
|
this.#abortController = undefined;
|
|
1357
1384
|
this.#activeRunId = undefined;
|
|
1385
|
+
this.#activeResourceRunId = undefined;
|
|
1358
1386
|
this.#runningPrompt = undefined;
|
|
1359
1387
|
this.#resolveRunningPrompt = undefined;
|
|
1360
1388
|
resolve();
|
|
@@ -1428,6 +1456,7 @@ export class Agent {
|
|
|
1428
1456
|
maxRetryDelayMs: this.#maxRetryDelayMs,
|
|
1429
1457
|
requestMaxRetries: this.#requestMaxRetries,
|
|
1430
1458
|
streamMaxRetries: this.#streamMaxRetries,
|
|
1459
|
+
streamFirstEventTimeoutMs: this.#streamFirstEventTimeoutMs,
|
|
1431
1460
|
...(fallbackManaged
|
|
1432
1461
|
? {
|
|
1433
1462
|
fallbackManaged: true,
|
|
@@ -1451,6 +1480,8 @@ export class Agent {
|
|
|
1451
1480
|
onResponse: this.#onResponse,
|
|
1452
1481
|
onSseEvent: this.#onSseEvent,
|
|
1453
1482
|
signal: abortController.signal,
|
|
1483
|
+
resourceLedger: this.resourceLedger,
|
|
1484
|
+
resourceRunId: this.#activeResourceRunId,
|
|
1454
1485
|
getApiKey: this.getApiKey,
|
|
1455
1486
|
getAuthCredentialType: this.getAuthCredentialType,
|
|
1456
1487
|
getToolContext: this.#getToolContext,
|
|
@@ -1697,6 +1728,7 @@ export class Agent {
|
|
|
1697
1728
|
this.#state.pendingToolCalls = new Set<string>();
|
|
1698
1729
|
this.#abortController = undefined;
|
|
1699
1730
|
this.#activeRunId = undefined;
|
|
1731
|
+
this.#activeResourceRunId = undefined;
|
|
1700
1732
|
this.#activeFallbackManaged = false;
|
|
1701
1733
|
this.#resolveRunningPrompt?.();
|
|
1702
1734
|
this.#runningPrompt = undefined;
|
|
@@ -1755,8 +1787,13 @@ export class Agent {
|
|
|
1755
1787
|
if (this.#terminalizedLogicalRunIds.size > 256) {
|
|
1756
1788
|
this.#terminalizedLogicalRunIds.delete(this.#terminalizedLogicalRunIds.values().next().value!);
|
|
1757
1789
|
}
|
|
1758
|
-
|
|
1759
|
-
|
|
1790
|
+
try {
|
|
1791
|
+
beforeEvent?.();
|
|
1792
|
+
if (event) this.#emit(event);
|
|
1793
|
+
} finally {
|
|
1794
|
+
// Publish terminal lifecycle synchronously before sealing the stable handle.
|
|
1795
|
+
this.resourceLedger.seal(String(logicalRunId));
|
|
1796
|
+
}
|
|
1760
1797
|
}
|
|
1761
1798
|
|
|
1762
1799
|
#getAssistantTextLength(message: AgentMessage | null): number {
|
package/src/compaction/openai.ts
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
neutralizeResponsesInputControlTokens,
|
|
29
29
|
normalizeResponsesToolCallId,
|
|
30
30
|
} from "@gajae-code/ai/utils";
|
|
31
|
-
import { $
|
|
31
|
+
import { $credentialEnv, logger } from "@gajae-code/utils";
|
|
32
32
|
|
|
33
33
|
const OPENAI_DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
34
34
|
|
|
@@ -81,7 +81,8 @@ function resolveOpenAiCompactEndpoint(model: Model, authCredentialType?: "api_ke
|
|
|
81
81
|
return resolveOpenAiCodexCompactEndpoint(model.baseUrl);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
// Trusted sources only: the compaction endpoint carries the OpenAI credential.
|
|
85
|
+
const envBaseUrl = $credentialEnv("OPENAI_BASE_URL");
|
|
85
86
|
const configuredBaseUrl = model.baseUrl?.trim();
|
|
86
87
|
const rawBase =
|
|
87
88
|
authCredentialType === "oauth"
|
|
@@ -94,6 +95,11 @@ function resolveOpenAiCompactEndpoint(model: Model, authCredentialType?: "api_ke
|
|
|
94
95
|
return `${normalizedBase}/v1/responses/compact`;
|
|
95
96
|
}
|
|
96
97
|
|
|
98
|
+
/** Test seam: the compaction endpoint as resolved from trusted env. */
|
|
99
|
+
export function resolveOpenAiCompactEndpointForTest(model: Model, authCredentialType?: "api_key" | "oauth"): string {
|
|
100
|
+
return resolveOpenAiCompactEndpoint(model, authCredentialType);
|
|
101
|
+
}
|
|
102
|
+
|
|
97
103
|
function resolveOpenAiCodexCompactEndpoint(baseUrl: string | undefined): string {
|
|
98
104
|
const rawBase = baseUrl && baseUrl.length > 0 ? baseUrl : CODEX_BASE_URL;
|
|
99
105
|
const normalizedBase = rawBase.endsWith("/") ? rawBase.slice(0, -1) : rawBase;
|