@deepstrike/wasm 0.2.77 → 0.2.78
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/dist/agent.d.ts +6 -2
- package/dist/agent.js +59 -19
- package/dist/index.d.ts +7 -9
- package/dist/index.js +3 -5
- package/dist/memory/attestation.d.ts +38 -0
- package/dist/memory/attestation.js +43 -0
- package/dist/memory/authority.d.ts +2 -0
- package/dist/memory/authority.js +3 -1
- package/dist/memory/candidate-sink.d.ts +66 -0
- package/dist/memory/candidate-sink.js +82 -0
- package/dist/memory/durable.d.ts +4 -2
- package/dist/memory/durable.js +2 -0
- package/dist/memory/index.d.ts +9 -1
- package/dist/memory/index.js +5 -0
- package/dist/memory/lifecycle.d.ts +82 -0
- package/dist/memory/lifecycle.js +46 -0
- package/dist/memory/recall-projection.d.ts +5 -0
- package/dist/memory/recall-projection.js +18 -0
- package/dist/memory/runtime-policy.d.ts +15 -0
- package/dist/memory/runtime-policy.js +26 -0
- package/dist/memory/writer.d.ts +22 -0
- package/dist/memory/writer.js +41 -0
- package/dist/providers/anthropic-compaction.d.ts +84 -0
- package/dist/providers/anthropic-compaction.js +222 -0
- package/dist/providers/anthropic.d.ts +41 -1
- package/dist/providers/anthropic.js +187 -18
- package/dist/providers/base.js +11 -1
- package/dist/runtime/canonical-kernel-step.d.ts +1 -2
- package/dist/runtime/canonical-kernel-step.js +74 -8
- package/dist/runtime/execution-plane.js +1 -1
- package/dist/runtime/index.d.ts +0 -2
- package/dist/runtime/index.js +0 -1
- package/dist/runtime/kernel-event-log.d.ts +8 -0
- package/dist/runtime/kernel-event-log.js +61 -1
- package/dist/runtime/kernel-step.d.ts +13 -2
- package/dist/runtime/os-snapshot.js +1 -0
- package/dist/runtime/runner.d.ts +40 -25
- package/dist/runtime/runner.js +196 -240
- package/dist/runtime/session-event-registry.generated.d.ts +212 -0
- package/dist/runtime/session-event-registry.generated.js +112 -0
- package/dist/runtime/session-log.d.ts +69 -16
- package/dist/runtime/session-log.js +10 -58
- package/dist/runtime/session-repair.d.ts +0 -3
- package/dist/runtime/session-repair.js +0 -3
- package/dist/runtime/sub-agent-orchestrator.d.ts +2 -0
- package/dist/runtime/sub-agent-orchestrator.js +2 -0
- package/dist/runtime/types/agent.d.ts +9 -52
- package/dist/runtime/types/agent.js +8 -45
- package/dist/types.d.ts +10 -5
- package/package.json +3 -3
- package/dist/memory/extraction.d.ts +0 -4
- package/dist/memory/extraction.js +0 -48
- package/dist/runtime/context.d.ts +0 -28
- package/dist/runtime/context.js +0 -16
- package/dist/runtime/evolution.d.ts +0 -189
- package/dist/runtime/evolution.js +0 -25
- package/dist/runtime/reducers.d.ts +0 -15
- package/dist/runtime/reducers.js +0 -57
- package/dist/runtime/verifiable-report.d.ts +0 -59
- package/dist/runtime/verifiable-report.js +0 -64
- package/dist/runtime/workflow-control-flow.d.ts +0 -21
- package/dist/runtime/workflow-control-flow.js +0 -83
package/dist/runtime/runner.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { prepareProviderRequest } from "../providers/prepared-request.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { extractSessionMemories } from "../memory/extraction.js";
|
|
2
|
+
import { resolveMemoryRuntimePolicy } from "../memory/runtime-policy.js";
|
|
3
|
+
import { memoryCandidateId } from "../memory/candidate-sink.js";
|
|
5
4
|
import { resolvePermissionRequest } from "./execution-plane.js";
|
|
6
5
|
import { governancePolicyToKernelEvent } from "../governance.js";
|
|
7
6
|
import { parseToolCallArguments } from "./tool-arguments.js";
|
|
8
7
|
import { stripSkillFrontmatter } from "./execution-plane.js";
|
|
9
8
|
import { getKernel } from "./kernel.js";
|
|
10
9
|
import { checkMemoryWrite, deriveMemoryRecall } from "../memory/authority.js";
|
|
10
|
+
import { memoryFetchRecall } from "../memory/recall-projection.js";
|
|
11
|
+
import { MemoryWriter } from "../memory/writer.js";
|
|
11
12
|
import { CanonicalRunnerRuntime, canonicalKernelAction, canonicalKernelApply, isInvalidInputError, canonicalKernelMaybeAction, canonicalStartAgent, canonicalStartWorkflow, sha256 as canonicalSha256, } from "./canonical-kernel-step.js";
|
|
12
13
|
import { peekProviderReplay, seedProviderReplayFromEvents } from "./provider-replay.js";
|
|
13
14
|
import { sanitizeReplayText } from "./replay-sanitize.js";
|
|
@@ -18,8 +19,6 @@ import { messageToKernelMessage, archivePresentationFromObservations, skillMetad
|
|
|
18
19
|
import { agentRunSpecToKernel, MILESTONE_UNVERIFIED_REASON, milestoneCheckFail, milestoneCheckPass, milestoneCheckResultToKernel, subAgentResultToKernel, workflowBudgetNote, workflowNodeSpecToKernel, workflowNodeOutcomeFromKernel, workflowNodeStatusFromTermination, workflowNodeToManifest, workflowNodeToSpec, workflowSpecToKernel, } from "./types/agent.js";
|
|
19
20
|
import { defaultSubAgentOrchestrator } from "./sub-agent-orchestrator.js";
|
|
20
21
|
import { extractJsonValue, schemaInstruction, schemaRetryInstruction, validateAgainstSchema, } from "./output-schema.js";
|
|
21
|
-
import { resolveReducer } from "./reducers.js";
|
|
22
|
-
import { loopInstruction, classifyInstruction, judgeGoal, dependencyOutputsNote, extractClassifyBranch, extractJudgeWinner, } from "./workflow-control-flow.js";
|
|
23
22
|
import { kernelObservationToSessionEvent } from "./kernel-event-log.js";
|
|
24
23
|
import { assertNativeProfile } from "./os-profile.js";
|
|
25
24
|
import { classifyProviderError, providerErrorEventFields } from "../providers/provider-error.js";
|
|
@@ -107,8 +106,19 @@ function controlRequestRejection(observations, operation) {
|
|
|
107
106
|
reason: typeof rejected.reason === "string" ? rejected.reason : "request denied",
|
|
108
107
|
};
|
|
109
108
|
}
|
|
109
|
+
/** The kernel's wire form of the tiers a provider performs natively, or nothing when it performs
|
|
110
|
+
* none — an operation that delegates nothing configures exactly as before. */
|
|
111
|
+
export function delegatedContextTiers(native) {
|
|
112
|
+
if (!native?.toolResultClearing && !native?.compaction)
|
|
113
|
+
return undefined;
|
|
114
|
+
return {
|
|
115
|
+
...(native.toolResultClearing ? { tool_result_clearing: true } : {}),
|
|
116
|
+
...(native.compaction ? { compaction: true } : {}),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
110
119
|
export class RuntimeRunner {
|
|
111
120
|
opts;
|
|
121
|
+
memoryRuntimeGates;
|
|
112
122
|
interrupted = false;
|
|
113
123
|
cancellationReason;
|
|
114
124
|
/** #2-B-ii: aborts the in-flight provider stream on interrupt/preempt. Recreated per `execute`. */
|
|
@@ -147,6 +157,10 @@ export class RuntimeRunner {
|
|
|
147
157
|
activeProviderInvocationId;
|
|
148
158
|
constructor(opts) {
|
|
149
159
|
this.opts = opts;
|
|
160
|
+
this.memoryRuntimeGates = resolveMemoryRuntimePolicy(opts.memoryRuntimePolicy);
|
|
161
|
+
if (this.memoryPathToCandidateSink("modelWrites") && !opts.memoryCandidateSink) {
|
|
162
|
+
throw new Error('memory runtime policy modelWrites = "candidate_sink" needs RuntimeOptions.memoryCandidateSink');
|
|
163
|
+
}
|
|
150
164
|
const schemaAttempts = opts.workflowSchemaValidationAttempts ?? 2;
|
|
151
165
|
if (!Number.isInteger(schemaAttempts) || schemaAttempts < 1 || schemaAttempts > 16) {
|
|
152
166
|
throw new RangeError("workflowSchemaValidationAttempts must be an integer between 1 and 16");
|
|
@@ -181,7 +195,6 @@ export class RuntimeRunner {
|
|
|
181
195
|
maxTurns: this.opts.maxTurns,
|
|
182
196
|
maxTotalTokens: this.opts.maxTotalTokens,
|
|
183
197
|
maxWallMs: this.opts.timeoutMs,
|
|
184
|
-
artifactSetDigest: this.opts.artifactSetDigest,
|
|
185
198
|
memoryBindingId: `wasm-memory-${this.opts.agentId ?? "root"}`,
|
|
186
199
|
persistPayload: async (_callId, content, previewBytes) => {
|
|
187
200
|
const digest = canonicalSha256(content);
|
|
@@ -346,9 +359,9 @@ export class RuntimeRunner {
|
|
|
346
359
|
* §22.13 · a host-authored memory write. The kernel decides whether it may happen: a live
|
|
347
360
|
* operation answers through `admit_memory_write` (the model's validation rule and rolling write
|
|
348
361
|
* quota); with no live operation the same kernel rule answers statelessly. Resolves `true` when
|
|
349
|
-
* the record was persisted.
|
|
362
|
+
* the record was persisted or submitted as a pending candidate.
|
|
350
363
|
*/
|
|
351
|
-
async writeMemory(memory, sessionId) {
|
|
364
|
+
async writeMemory(memory, sessionId, candidate) {
|
|
352
365
|
if (!this.opts.memoryStore || !this.opts.agentId)
|
|
353
366
|
return false;
|
|
354
367
|
const turn = this.activeKernel?.turn() ?? 0;
|
|
@@ -361,6 +374,12 @@ export class RuntimeRunner {
|
|
|
361
374
|
}
|
|
362
375
|
return false;
|
|
363
376
|
}
|
|
377
|
+
if (candidate) {
|
|
378
|
+
const receipt = await this.memoryWriter().propose(this.opts.agentId, { candidate_id: candidate.candidateId, source: candidate.source, record: memory });
|
|
379
|
+
if (sessionId)
|
|
380
|
+
await this.opts.sessionLog.append(sessionId, this.memoryCandidateEvent(receipt, candidate.source, memory));
|
|
381
|
+
return receipt.status !== "rejected";
|
|
382
|
+
}
|
|
364
383
|
try {
|
|
365
384
|
await this.opts.memoryStore.put(this.opts.agentId, memory);
|
|
366
385
|
}
|
|
@@ -376,6 +395,114 @@ export class RuntimeRunner {
|
|
|
376
395
|
}
|
|
377
396
|
return true;
|
|
378
397
|
}
|
|
398
|
+
/**
|
|
399
|
+
* M4 · a host-initiated recall (an explicit `recall`). Same path as the prefetch: the retrieval
|
|
400
|
+
* gate, the policy's `retrievalTopK`, the kernel-derived recall lifecycle, and a
|
|
401
|
+
* `memory_retrieval_result` audit.
|
|
402
|
+
*/
|
|
403
|
+
async queryMemory(query, sessionId) {
|
|
404
|
+
if (!this.opts.memoryStore || !this.opts.agentId)
|
|
405
|
+
return [];
|
|
406
|
+
if (!this.memoryPathEnabled("retrievalEnabled"))
|
|
407
|
+
return [];
|
|
408
|
+
const policyLimit = this.opts.memoryPolicy?.retrievalTopK;
|
|
409
|
+
const limit = policyLimit === undefined ? query.top_k : Math.min(query.top_k, policyLimit);
|
|
410
|
+
if (limit <= 0)
|
|
411
|
+
return [];
|
|
412
|
+
const hits = (await this.opts.memoryStore.search(this.opts.agentId, { ...query, top_k: limit })).slice(0, limit);
|
|
413
|
+
await this.recordHostMemoryRecall(hits);
|
|
414
|
+
if (sessionId)
|
|
415
|
+
await this.opts.sessionLog.append(sessionId, { kind: "memory_retrieval_result", hits });
|
|
416
|
+
return hits;
|
|
417
|
+
}
|
|
418
|
+
async persistMemoryEffectResult(operationId, effectId, canonicalMemory) {
|
|
419
|
+
const agentId = this.opts.agentId;
|
|
420
|
+
const record = {
|
|
421
|
+
record_id: `memory:${crypto.randomUUID()}`,
|
|
422
|
+
scope: this.opts.memoryScope ?? { tenant_id: "default", namespace: agentId ?? "default" },
|
|
423
|
+
name: String(canonicalMemory.name ?? ""),
|
|
424
|
+
kind: String(canonicalMemory.kind ?? "reference"),
|
|
425
|
+
content: String(canonicalMemory.content ?? ""),
|
|
426
|
+
description: String(canonicalMemory.description ?? ""),
|
|
427
|
+
provenance: {
|
|
428
|
+
author: "model",
|
|
429
|
+
trust: "untrusted",
|
|
430
|
+
evidence_refs: Array.isArray(canonicalMemory.evidence_refs)
|
|
431
|
+
? canonicalMemory.evidence_refs.map(String)
|
|
432
|
+
: [],
|
|
433
|
+
},
|
|
434
|
+
created_at: Number(canonicalMemory.accepted_at_ms ?? Date.now()),
|
|
435
|
+
updated_at: Number(canonicalMemory.accepted_at_ms ?? Date.now()),
|
|
436
|
+
recall_count: 0,
|
|
437
|
+
confidence: 1,
|
|
438
|
+
links: [],
|
|
439
|
+
pinned: false,
|
|
440
|
+
};
|
|
441
|
+
if (this.memoryPathToCandidateSink("modelWrites")) {
|
|
442
|
+
try {
|
|
443
|
+
if (!agentId)
|
|
444
|
+
throw new Error("memory persistence requires RuntimeOptions.agentId");
|
|
445
|
+
const modelProposal = Boolean(canonicalMemory.causation && typeof canonicalMemory.causation === "object" && canonicalMemory.causation.kind === "provider_tool");
|
|
446
|
+
const source = modelProposal ? "model_proposal" : "child_request";
|
|
447
|
+
// Child requests keep their v2 identity so in-flight redeliveries still match the sink.
|
|
448
|
+
const candidateId = modelProposal
|
|
449
|
+
? await memoryCandidateId(["v3", agentId, "model_proposal", operationId, effectId, "0"])
|
|
450
|
+
: await memoryCandidateId(["v2", agentId, "child_request", operationId, effectId, "0"]);
|
|
451
|
+
const receipt = await this.memoryWriter().propose(agentId, { candidate_id: candidateId, source, record });
|
|
452
|
+
return { kind: "memory_candidate_result", effect_id: effectId, ...receipt };
|
|
453
|
+
}
|
|
454
|
+
catch (cause) {
|
|
455
|
+
return { kind: "memory_candidate_result", effect_id: effectId, error: formatToolError(cause) };
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
try {
|
|
459
|
+
if (!this.memoryPathEnabled("modelWritesEnabled")) {
|
|
460
|
+
throw new Error("model memory writes are disabled by memoryRuntimePolicy.modelWrites");
|
|
461
|
+
}
|
|
462
|
+
if (!agentId)
|
|
463
|
+
throw new Error("memory persistence requires RuntimeOptions.agentId");
|
|
464
|
+
// The receipt names what the store now holds: the record's id and its content digest.
|
|
465
|
+
const receipt = await this.memoryWriter().persist(agentId, record);
|
|
466
|
+
return { kind: "memory_persist_result", effect_id: effectId, ...receipt };
|
|
467
|
+
}
|
|
468
|
+
catch (cause) {
|
|
469
|
+
return { kind: "memory_persist_result", effect_id: effectId, error: formatToolError(cause) };
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/** The host's side of every memory write: the store, or the candidate sink's receipt contract. */
|
|
473
|
+
memoryWriter() {
|
|
474
|
+
return new MemoryWriter({ store: this.opts.memoryStore, sink: this.opts.memoryCandidateSink });
|
|
475
|
+
}
|
|
476
|
+
/** The audit fact for a sink's answer. Only an accepted candidate is a written record. */
|
|
477
|
+
memoryCandidateEvent(receipt, source, memory) {
|
|
478
|
+
const turn = this.activeKernel?.turn() ?? 0;
|
|
479
|
+
switch (receipt.status) {
|
|
480
|
+
case "pending":
|
|
481
|
+
return {
|
|
482
|
+
kind: "memory_candidate_pending", turn, candidate_id: receipt.candidate_id, source,
|
|
483
|
+
name: memory.name, receipt_id: receipt.receipt_id,
|
|
484
|
+
};
|
|
485
|
+
case "rejected":
|
|
486
|
+
return {
|
|
487
|
+
kind: "memory_candidate_rejected", turn, candidate_id: receipt.candidate_id, source,
|
|
488
|
+
name: memory.name, receipt_id: receipt.receipt_id, reason_code: receipt.reason_code,
|
|
489
|
+
};
|
|
490
|
+
case "accepted":
|
|
491
|
+
return {
|
|
492
|
+
kind: "memory_written", turn, record_id: receipt.record_ref, scope: memory.scope,
|
|
493
|
+
memory_kind: memory.kind, name: memory.name, size_bytes: new TextEncoder().encode(memory.content).byteLength,
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
/** Host memory-policy gate: a path is on unless the host set its switch to `"disabled"`. */
|
|
498
|
+
memoryPathEnabled(path) {
|
|
499
|
+
return this.memoryRuntimeGates?.[path] ?? true;
|
|
500
|
+
}
|
|
501
|
+
/** M2 · whether a write path hands its writes to the candidate sink. Off unless the host set the
|
|
502
|
+
* path to `"candidate_sink"` — unlike the on/off gates, the default here is the store. */
|
|
503
|
+
memoryPathToCandidateSink(path) {
|
|
504
|
+
return this.memoryRuntimeGates?.[`${path}ToCandidateSink`] ?? false;
|
|
505
|
+
}
|
|
379
506
|
async admitMemoryWrite(memory) {
|
|
380
507
|
const runtime = this.activeKernel;
|
|
381
508
|
if (runtime && runtime.hasStarted() && !runtime.isTerminal()) {
|
|
@@ -624,6 +751,13 @@ export class RuntimeRunner {
|
|
|
624
751
|
tokens: Math.max(1, Math.ceil(this.opts.systemPrompt.length / 4)),
|
|
625
752
|
});
|
|
626
753
|
}
|
|
754
|
+
for (const [agentId, content] of Object.entries(this.opts.dependencyOutputs ?? {})) {
|
|
755
|
+
await this.commitKernelApply(runtime, this.pendingObservations, {
|
|
756
|
+
kind: "add_dependency_output",
|
|
757
|
+
agent_id: agentId,
|
|
758
|
+
content,
|
|
759
|
+
});
|
|
760
|
+
}
|
|
627
761
|
if (this.opts.initialMemory) {
|
|
628
762
|
for (const mem of this.opts.initialMemory) {
|
|
629
763
|
await this.commitKernelApply(runtime, this.pendingObservations, {
|
|
@@ -652,7 +786,7 @@ export class RuntimeRunner {
|
|
|
652
786
|
});
|
|
653
787
|
}
|
|
654
788
|
if (this.opts.memoryStore && this.opts.agentId) {
|
|
655
|
-
await this.commitKernelApply(runtime, this.pendingObservations, { kind: "set_memory_enabled", enabled: true });
|
|
789
|
+
await this.commitKernelApply(runtime, this.pendingObservations, { kind: "set_memory_enabled", enabled: true, read: this.memoryPathEnabled("retrievalEnabled"), write: this.memoryPathEnabled("modelWritesEnabled"), propose_memory: Boolean(this.opts.memoryCandidateSink && this.memoryPathToCandidateSink("modelWrites")), recall: Boolean(this.opts.memoryScope) });
|
|
656
790
|
}
|
|
657
791
|
if (this.opts.knowledgeSource) {
|
|
658
792
|
await this.commitKernelApply(runtime, this.pendingObservations, { kind: "set_knowledge_enabled", enabled: true });
|
|
@@ -748,14 +882,9 @@ export class RuntimeRunner {
|
|
|
748
882
|
}
|
|
749
883
|
if (!resumeMidRun)
|
|
750
884
|
await this.applyKernelPolicies(runtime);
|
|
751
|
-
// I4: pre-fetch memory before the first LLM turn (mirrors Node).
|
|
752
|
-
//
|
|
753
|
-
// ordinary `memory` tool result, so it decays with the compression pyramid instead of
|
|
754
|
-
// pinning itself in `knowledge` forever.
|
|
885
|
+
// I4: pre-fetch memory before the first LLM turn (mirrors Node). Each hit is an unpinned keyed
|
|
886
|
+
// `memory:<record_id>` knowledge entry, evicted at a boundary when usage needs the room.
|
|
755
887
|
this.currentGoal = goal;
|
|
756
|
-
if (!resumeMidRun) {
|
|
757
|
-
await this.prefetchMemoryIntoHistory(runtime, "initial");
|
|
758
|
-
}
|
|
759
888
|
let action = resumeMidRun
|
|
760
889
|
? runtime.resumeAction() ?? (() => { throw new Error("restored canonical operation has no pending effect or terminal"); })()
|
|
761
890
|
: await canonicalStartAgent(runtime, this.pendingObservations, startTask, startRunSpec);
|
|
@@ -885,18 +1014,6 @@ export class RuntimeRunner {
|
|
|
885
1014
|
this.providerRetryPending = action.kind === "call_provider";
|
|
886
1015
|
continue;
|
|
887
1016
|
}
|
|
888
|
-
if (!promptMeasurement)
|
|
889
|
-
throw new Error("context preparation requires prompt measurement");
|
|
890
|
-
const contextAdapter = await createNativeContextPreparationAdapter();
|
|
891
|
-
const preparation = contextAdapter.prepare({
|
|
892
|
-
effect: action.contextEffect,
|
|
893
|
-
request_fingerprint: providerPlan.fingerprint,
|
|
894
|
-
provider_route: { ...this.providerRoute, request_fingerprint_scope: preparedRequest.scope },
|
|
895
|
-
prompt_measurement: promptMeasurement,
|
|
896
|
-
});
|
|
897
|
-
await this.opts.sessionLog.append(sessionId, {
|
|
898
|
-
kind: "context_prepared", turn: runtime.turn(), effect_id: providerEffectId, preparation,
|
|
899
|
-
});
|
|
900
1017
|
const abortSignal = this.abortController?.signal;
|
|
901
1018
|
try {
|
|
902
1019
|
for await (const evt of preparedRequest.stream(abortSignal)) {
|
|
@@ -1122,56 +1239,28 @@ export class RuntimeRunner {
|
|
|
1122
1239
|
});
|
|
1123
1240
|
}
|
|
1124
1241
|
else if (action.kind === "persist_memory") {
|
|
1125
|
-
|
|
1126
|
-
// build the full record here, and let the receipt name exactly what the store now holds.
|
|
1127
|
-
const canonicalMemory = action.memory;
|
|
1128
|
-
const acceptedAt = Number(canonicalMemory.accepted_at_ms ?? Date.now());
|
|
1129
|
-
const record = {
|
|
1130
|
-
record_id: `memory:${crypto.randomUUID()}`,
|
|
1131
|
-
scope: this.opts.memoryScope ?? { tenant_id: "default", namespace: this.opts.agentId ?? "default" },
|
|
1132
|
-
name: String(canonicalMemory.name ?? ""),
|
|
1133
|
-
kind: String(canonicalMemory.kind ?? "reference"),
|
|
1134
|
-
content: String(canonicalMemory.content ?? ""),
|
|
1135
|
-
description: String(canonicalMemory.description ?? ""),
|
|
1136
|
-
provenance: {
|
|
1137
|
-
author: "model",
|
|
1138
|
-
trust: "untrusted",
|
|
1139
|
-
evidence_refs: Array.isArray(canonicalMemory.evidence_refs) ? canonicalMemory.evidence_refs.map(String) : [],
|
|
1140
|
-
},
|
|
1141
|
-
created_at: acceptedAt,
|
|
1142
|
-
updated_at: acceptedAt,
|
|
1143
|
-
recall_count: 0,
|
|
1144
|
-
confidence: 1,
|
|
1145
|
-
links: [],
|
|
1146
|
-
pinned: false,
|
|
1147
|
-
};
|
|
1148
|
-
let error;
|
|
1149
|
-
try {
|
|
1150
|
-
if (!this.opts.memoryStore || !this.opts.agentId)
|
|
1151
|
-
throw new Error("WASM memory persistence requires memoryStore and agentId");
|
|
1152
|
-
await this.opts.memoryStore.put(this.opts.agentId, record);
|
|
1153
|
-
}
|
|
1154
|
-
catch (cause) {
|
|
1155
|
-
error = formatToolError(cause);
|
|
1156
|
-
}
|
|
1157
|
-
action = await this.commitKernelAction(runtime, this.pendingObservations, {
|
|
1158
|
-
kind: "memory_persist_result",
|
|
1159
|
-
effect_id: action.effectId,
|
|
1160
|
-
...(error ? { error } : {
|
|
1161
|
-
record_ref: record.record_id,
|
|
1162
|
-
digest: `sha256:${sha256Hex(record.content)}`,
|
|
1163
|
-
}),
|
|
1164
|
-
});
|
|
1242
|
+
action = await this.commitKernelAction(runtime, this.pendingObservations, await this.persistMemoryEffectResult(runtime.operationId, action.effectId, action.memory));
|
|
1165
1243
|
}
|
|
1166
1244
|
else if (action.kind === "query_memory") {
|
|
1167
1245
|
let hits = [];
|
|
1168
1246
|
let error;
|
|
1169
1247
|
try {
|
|
1248
|
+
if (!this.memoryPathEnabled("retrievalEnabled"))
|
|
1249
|
+
throw new Error("memory retrieval is disabled by memoryRuntimePolicy.retrieval");
|
|
1170
1250
|
if (!this.opts.memoryStore || !this.opts.agentId)
|
|
1171
1251
|
throw new Error("WASM memory queries require memoryStore and agentId");
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1252
|
+
const recordId = typeof action.query.record_id === "string" ? action.query.record_id : undefined;
|
|
1253
|
+
const causation = action.query.causation;
|
|
1254
|
+
hits = causation?.kind === "kernel_recall"
|
|
1255
|
+
? await this.kernelRecallHits(String(action.query.text ?? ""), action.requestedK, causation.sprint ? "renewal" : "initial")
|
|
1256
|
+
: recordId === undefined
|
|
1257
|
+
? await this.opts.memoryStore.search(this.opts.agentId, {
|
|
1258
|
+
...action.query, top_k: action.requestedK,
|
|
1259
|
+
})
|
|
1260
|
+
: memoryFetchRecall(await this.opts.memoryStore.get(this.opts.agentId, recordId), {
|
|
1261
|
+
scope: this.opts.memoryScope ?? { tenant_id: "default", namespace: this.opts.agentId },
|
|
1262
|
+
kinds: Array.isArray(action.query.kinds) ? action.query.kinds.map(String) : [],
|
|
1263
|
+
}, Date.now());
|
|
1175
1264
|
}
|
|
1176
1265
|
catch (cause) {
|
|
1177
1266
|
error = formatToolError(cause);
|
|
@@ -1183,6 +1272,9 @@ export class RuntimeRunner {
|
|
|
1183
1272
|
hits,
|
|
1184
1273
|
...(error ? { error } : {}),
|
|
1185
1274
|
});
|
|
1275
|
+
if (!error && hits.length > 0 && this.currentSessionId) {
|
|
1276
|
+
await this.opts.sessionLog.append(this.currentSessionId, { kind: "memory_retrieval_result", hits });
|
|
1277
|
+
}
|
|
1186
1278
|
// M3/M4: mirror the kernel's journaled recall lifecycle + surface promotion suggestions.
|
|
1187
1279
|
for (const obs of this.pendingObservations.slice(obsStart)) {
|
|
1188
1280
|
if (obs.kind === "memory_recalled" && obs.recalls?.length && this.opts.agentId) {
|
|
@@ -1196,7 +1288,7 @@ export class RuntimeRunner {
|
|
|
1196
1288
|
else if (action.kind === "archive_page_out") {
|
|
1197
1289
|
const archiveMeta = this.activePageOutArchive
|
|
1198
1290
|
?? this.pendingPageOutArchives.shift()
|
|
1199
|
-
?? { archiveStart: this.nextArchiveStart, compressedSeq: await this.opts.sessionLog.latestSeq(sessionId) };
|
|
1291
|
+
?? { archiveStart: this.nextArchiveStart, compressedSeq: await this.opts.sessionLog.latestSeq(sessionId), action: action.action, tier: action.tier };
|
|
1200
1292
|
this.activePageOutArchive = archiveMeta;
|
|
1201
1293
|
let archiveRef;
|
|
1202
1294
|
let error;
|
|
@@ -1212,9 +1304,6 @@ export class RuntimeRunner {
|
|
|
1212
1304
|
catch (cause) {
|
|
1213
1305
|
error = formatToolError(cause);
|
|
1214
1306
|
}
|
|
1215
|
-
const archived = action.archived;
|
|
1216
|
-
const archiveAction = archiveMeta.action ?? "auto_compact";
|
|
1217
|
-
const archiveTier = archiveMeta.tier;
|
|
1218
1307
|
if (!error)
|
|
1219
1308
|
this.activePageOutArchive = undefined;
|
|
1220
1309
|
action = await this.commitKernelAction(runtime, this.pendingObservations, {
|
|
@@ -1223,9 +1312,6 @@ export class RuntimeRunner {
|
|
|
1223
1312
|
...(archiveRef ? { archive_ref: archiveRef } : {}),
|
|
1224
1313
|
...(error ? { error } : {}),
|
|
1225
1314
|
});
|
|
1226
|
-
if (!error && archiveTier === "semantic" && archived.length > 0) {
|
|
1227
|
-
void this.archiveSemanticPageOut(archived, archiveAction);
|
|
1228
|
-
}
|
|
1229
1315
|
}
|
|
1230
1316
|
else if (action.kind === "load_payload") {
|
|
1231
1317
|
const content = await this.payloadStore().loadPayload(sessionId, action.payloadRef);
|
|
@@ -1552,11 +1638,6 @@ export class RuntimeRunner {
|
|
|
1552
1638
|
updatedAtMs: Date.now(),
|
|
1553
1639
|
};
|
|
1554
1640
|
await this.opts.memoryStore.saveSession(completedSession);
|
|
1555
|
-
if (this.opts.memoryScope) {
|
|
1556
|
-
const extracted = await extractSessionMemories(this.opts.memoryProvider ?? this.opts.provider, completedSession, this.opts.memoryScope, this.opts.memorySystemPrompt);
|
|
1557
|
-
for (const memory of extracted)
|
|
1558
|
-
await this.writeMemory(memory, sessionId);
|
|
1559
|
-
}
|
|
1560
1641
|
}
|
|
1561
1642
|
catch { /* non-fatal */ }
|
|
1562
1643
|
}
|
|
@@ -1579,24 +1660,20 @@ export class RuntimeRunner {
|
|
|
1579
1660
|
* fed back on mismatch. If it still does not conform, the node is failed with the validation
|
|
1580
1661
|
* reason (an `Error`-terminated result fails the node in-kernel, starving its dependents).
|
|
1581
1662
|
*/
|
|
1582
|
-
async runWorkflowNode(node, parentSessionId, orchestrator, budget,
|
|
1583
|
-
// G2: a reduce node runs no LLM — execute the registered pure function over its dependency
|
|
1584
|
-
// outputs and feed the result back as an ordinary completion. Deterministic; no agent burned.
|
|
1585
|
-
if (node.reducer) {
|
|
1586
|
-
return this.runReduceNode(node, outputs ?? new Map());
|
|
1587
|
-
}
|
|
1663
|
+
async runWorkflowNode(node, parentSessionId, orchestrator, budget, abortSignal) {
|
|
1588
1664
|
const baseSpec = workflowNodeToSpec(node, parentSessionId);
|
|
1589
1665
|
const manifest = workflowNodeToManifest(node, parentSessionId);
|
|
1590
1666
|
// G4: surface remaining workflow budget so a coordinator node can size its submission.
|
|
1591
1667
|
const budgetNote = workflowBudgetNote(budget);
|
|
1592
|
-
//
|
|
1593
|
-
|
|
1594
|
-
const depsNote = dependencyOutputsNote(node.input_agent_ids, outputs);
|
|
1595
|
-
const withBudget = (goal) => [goal, depsNote, budgetNote].filter(Boolean).join("\n\n");
|
|
1668
|
+
// A DAG edge carries data: the kernel composes the dependency section of the brief.
|
|
1669
|
+
const withBudget = (goal) => [goal, node.dependency_brief, budgetNote].filter(Boolean).join("\n\n");
|
|
1596
1670
|
const mkCtx = (goal) => ({
|
|
1597
1671
|
parentOpts: this.opts,
|
|
1598
1672
|
parentSessionId,
|
|
1599
1673
|
spec: { ...baseSpec, goal: withBudget(goal) },
|
|
1674
|
+
...(node.dependency_outputs
|
|
1675
|
+
? { dependencyOutputs: node.dependency_outputs }
|
|
1676
|
+
: {}),
|
|
1600
1677
|
manifest,
|
|
1601
1678
|
sessionLog: this.opts.sessionLog,
|
|
1602
1679
|
// This child is a workflow node, so capability resolution applies workflow-node quarantine
|
|
@@ -1609,39 +1686,6 @@ export class RuntimeRunner {
|
|
|
1609
1686
|
// #2-B-ii: the per-node abort signal the driver fires when the kernel preempts this node.
|
|
1610
1687
|
...(abortSignal ? { abortSignal } : {}),
|
|
1611
1688
|
});
|
|
1612
|
-
const textOf = (r) => {
|
|
1613
|
-
const c = r.result.finalMessage?.content;
|
|
1614
|
-
return typeof c === "string" ? c : c != null ? JSON.stringify(c) : "";
|
|
1615
|
-
};
|
|
1616
|
-
const withSignal = (r, patch) => ({ ...r, result: { ...r.result, ...patch } });
|
|
1617
|
-
// A#2 tournament judge: compare two entrants' produced outputs rather than running the node's own
|
|
1618
|
-
// goal. Look up both candidates, judge over the controller's criterion, and report the winner's id.
|
|
1619
|
-
if (node.judge_match) {
|
|
1620
|
-
const out = outputs ?? new Map();
|
|
1621
|
-
const left = out.get(node.judge_match.left) ?? "";
|
|
1622
|
-
const right = out.get(node.judge_match.right) ?? "";
|
|
1623
|
-
const result = await orchestrator.run(mkCtx(judgeGoal(baseSpec.goal, left, right)));
|
|
1624
|
-
const winner = extractJudgeWinner(textOf(result));
|
|
1625
|
-
const winnerId = winner === "right" ? node.judge_match.right : node.judge_match.left;
|
|
1626
|
-
return withSignal(result, { tournamentWinner: winnerId });
|
|
1627
|
-
}
|
|
1628
|
-
// loop-control loop iteration: run the increment under the armed pacing trap (workflowNodeToSpec set
|
|
1629
|
-
// `loopRound`, and the iteration resumes the loop's stable session — transcript-as-carry).
|
|
1630
|
-
// The kernel-adjudicated `pace` verb is the only continuation signal. Ending without a pace
|
|
1631
|
-
// decision completes the loop.
|
|
1632
|
-
if (node.loop_max_iters != null) {
|
|
1633
|
-
const iteration = Number(/-i(\d+)$/.exec(node.agent_id)?.[1] ?? "0");
|
|
1634
|
-
const result = await orchestrator.run(mkCtx(`${baseSpec.goal}\n\n${loopInstruction(node.loop_max_iters, iteration)}`));
|
|
1635
|
-
const pace = result.result.paceDecision;
|
|
1636
|
-
return withSignal(result, { loopContinue: pace?.action === "continue" });
|
|
1637
|
-
}
|
|
1638
|
-
// A#2 classify: run the classifier, then extract the chosen branch label (kernel prunes the rest).
|
|
1639
|
-
if (node.classify_labels && node.classify_labels.length) {
|
|
1640
|
-
const labels = node.classify_labels;
|
|
1641
|
-
const result = await orchestrator.run(mkCtx(`${baseSpec.goal}\n\n${classifyInstruction(labels)}`));
|
|
1642
|
-
const branch = extractClassifyBranch(textOf(result), labels);
|
|
1643
|
-
return branch === undefined ? result : withSignal(result, { classifyBranch: branch });
|
|
1644
|
-
}
|
|
1645
1689
|
const schema = node.output_schema;
|
|
1646
1690
|
if (!schema)
|
|
1647
1691
|
return orchestrator.run(mkCtx(baseSpec.goal));
|
|
@@ -1672,27 +1716,6 @@ export class RuntimeRunner {
|
|
|
1672
1716
|
},
|
|
1673
1717
|
};
|
|
1674
1718
|
}
|
|
1675
|
-
/**
|
|
1676
|
-
* G2: execute a deterministic reduce node — run the named reducer (built-ins overlaid with
|
|
1677
|
-
* `opts.reducers`) over its dependency outputs and return a synthetic completion. No LLM, zero
|
|
1678
|
-
* tokens. An unknown reducer or a thrown reducer fails the node (`Error` → starves dependents).
|
|
1679
|
-
*/
|
|
1680
|
-
runReduceNode(node, outputs) {
|
|
1681
|
-
const ok = (content, termination) => ({
|
|
1682
|
-
agentId: node.agent_id,
|
|
1683
|
-
result: { termination, finalMessage: { role: "assistant", content, toolCalls: [] }, turnsUsed: 0, totalTokensUsed: 0 },
|
|
1684
|
-
});
|
|
1685
|
-
const reducer = resolveReducer(node.reducer, this.opts.reducers);
|
|
1686
|
-
if (!reducer)
|
|
1687
|
-
return ok(`unknown reducer "${node.reducer}"`, "error");
|
|
1688
|
-
const inputs = (node.input_agent_ids ?? []).map(agentId => ({ agentId, output: outputs.get(agentId) ?? "" }));
|
|
1689
|
-
try {
|
|
1690
|
-
return ok(reducer(inputs), "completed");
|
|
1691
|
-
}
|
|
1692
|
-
catch (err) {
|
|
1693
|
-
return ok(`reducer "${node.reducer}" threw: ${formatToolError(err)}`, "error");
|
|
1694
|
-
}
|
|
1695
|
-
}
|
|
1696
1719
|
/**
|
|
1697
1720
|
* W0-ABI: run a declarative workflow DAG. The kernel owns the DAG and gates every node spawn
|
|
1698
1721
|
* through the syscall trap; this driver runs each kernel-emitted batch of nodes in parallel,
|
|
@@ -1715,6 +1738,10 @@ export class RuntimeRunner {
|
|
|
1715
1738
|
if (this.opts.contextPolicy) {
|
|
1716
1739
|
config.context_policy = normalizeContextPolicy(contextPolicy(this.opts.contextPolicy));
|
|
1717
1740
|
}
|
|
1741
|
+
const delegated = delegatedContextTiers(this.opts.provider?.descriptor?.().nativeContext);
|
|
1742
|
+
if (delegated) {
|
|
1743
|
+
config.context_policy = { ...config.context_policy, delegated_tiers: delegated };
|
|
1744
|
+
}
|
|
1718
1745
|
config.signal_policy = {
|
|
1719
1746
|
queue_max: signalPolicy.queueMax,
|
|
1720
1747
|
...(signalPolicy.ttlMs !== undefined ? { ttl_ms: signalPolicy.ttlMs } : {}),
|
|
@@ -1971,7 +1998,7 @@ export class RuntimeRunner {
|
|
|
1971
1998
|
}
|
|
1972
1999
|
const controller = new AbortController();
|
|
1973
2000
|
controllers.set(node.agent_id, controller);
|
|
1974
|
-
const running = this.runWorkflowNode(node, parentSessionId, orchestrator, budget,
|
|
2001
|
+
const running = this.runWorkflowNode(node, parentSessionId, orchestrator, budget, controller.signal)
|
|
1975
2002
|
.then(result => ({ kind: "node", node, result }))
|
|
1976
2003
|
.finally(() => batchState.finished.add(node.agent_id));
|
|
1977
2004
|
// A node can fail while the driver is busy feeding another completion; the race observes
|
|
@@ -2004,15 +2031,10 @@ export class RuntimeRunner {
|
|
|
2004
2031
|
if (batchState.stopping)
|
|
2005
2032
|
return { spawned: [], done: undefined };
|
|
2006
2033
|
const { node, result } = landed;
|
|
2007
|
-
//
|
|
2034
|
+
// Record this node's output so its dependents can consume it.
|
|
2008
2035
|
const outContent = result.result.finalMessage?.content;
|
|
2009
2036
|
const outText = typeof outContent === "string" ? outContent : outContent != null ? JSON.stringify(outContent) : "";
|
|
2010
2037
|
outputs.set(result.agentId, outText);
|
|
2011
|
-
// A loop iteration completes under `wf-node{N}-i{k}` but its dependents consume the STABLE
|
|
2012
|
-
// node id `wf-node{N}` — alias it so the LAST iteration's output is what dependents see.
|
|
2013
|
-
const stableId = result.agentId.replace(/-i\d+$/, "");
|
|
2014
|
-
if (stableId !== result.agentId)
|
|
2015
|
-
outputs.set(stableId, outText);
|
|
2016
2038
|
const observationStart = this.pendingObservations.length;
|
|
2017
2039
|
const completionAction = await this.commitKernelMaybeAction(runtime, this.pendingObservations, {
|
|
2018
2040
|
kind: "sub_agent_completed",
|
|
@@ -2049,17 +2071,13 @@ export class RuntimeRunner {
|
|
|
2049
2071
|
}));
|
|
2050
2072
|
}
|
|
2051
2073
|
}
|
|
2052
|
-
// Persist node completion for resume recovery
|
|
2053
|
-
//
|
|
2054
|
-
// text (post-resume dependents/reduce still see this node's output).
|
|
2074
|
+
// Persist node completion for resume recovery, with the output text so post-resume
|
|
2075
|
+
// dependents still see this node's output.
|
|
2055
2076
|
await this.opts.sessionLog.append(parentSessionId, buildWorkflowNodeCompletedEvent({
|
|
2056
2077
|
turn: runtime.turn(),
|
|
2057
2078
|
agentId: result.agentId,
|
|
2058
2079
|
status: workflowNodeStatusFromTermination(result.result.termination),
|
|
2059
2080
|
termination: result.result.termination,
|
|
2060
|
-
classifyBranch: result.result.classifyBranch,
|
|
2061
|
-
tournamentWinner: result.result.tournamentWinner,
|
|
2062
|
-
loopContinue: result.result.loopContinue,
|
|
2063
2081
|
...(result.result.finalMessage ? { output: result.result.finalMessage } : {}),
|
|
2064
2082
|
}));
|
|
2065
2083
|
return { spawned, done: findDone(obs) };
|
|
@@ -2112,93 +2130,31 @@ export class RuntimeRunner {
|
|
|
2112
2130
|
}
|
|
2113
2131
|
nextArchiveStart = compressedSeq + 1;
|
|
2114
2132
|
}
|
|
2115
|
-
// K4: a sprint renewal dropped the old history — including any earlier memory hits — so
|
|
2116
|
-
// re-run the preQueryMemory prefetch for the new sprint (live observations only).
|
|
2117
|
-
if (obs.kind === "renewed") {
|
|
2118
|
-
await this.prefetchMemoryIntoHistory(runtime, "renewal");
|
|
2119
|
-
}
|
|
2120
2133
|
}
|
|
2121
2134
|
return nextArchiveStart;
|
|
2122
2135
|
}
|
|
2123
|
-
/**
|
|
2124
|
-
*
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
const
|
|
2137
|
-
|
|
2138
|
-
const seen = new Set();
|
|
2139
|
-
const recalled = [];
|
|
2140
|
-
for (const q of queries ?? []) {
|
|
2141
|
-
if (!q.query.trim())
|
|
2136
|
+
/** The kernel's own recall for the run goal (plan task 2.1). `preQueryMemory` may rewrite it
|
|
2137
|
+
* into several scoped queries; their hits are merged, one per record. */
|
|
2138
|
+
async kernelRecallHits(goal, requestedK, phase) {
|
|
2139
|
+
const scope = this.opts.memoryScope;
|
|
2140
|
+
const queries = this.opts.preQueryMemory
|
|
2141
|
+
? await this.opts.preQueryMemory({ goal, phase }) ?? []
|
|
2142
|
+
: [{ scope, query: goal, top_k: requestedK, kinds: [] }];
|
|
2143
|
+
const seen = new Set();
|
|
2144
|
+
const hits = [];
|
|
2145
|
+
for (const query of queries) {
|
|
2146
|
+
if (!query.query.trim())
|
|
2147
|
+
continue;
|
|
2148
|
+
const limit = Math.min(query.top_k ?? requestedK, requestedK);
|
|
2149
|
+
for (const hit of (await this.opts.memoryStore.search(this.opts.agentId, { ...query, top_k: limit })).slice(0, limit)) {
|
|
2150
|
+
if (seen.has(hit.record.record_id))
|
|
2142
2151
|
continue;
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
if (seen.has(hit.record.record_id))
|
|
2146
|
-
continue;
|
|
2147
|
-
seen.add(hit.record.record_id);
|
|
2148
|
-
recalled.push(hit);
|
|
2149
|
-
lines.push(`[memory record_id=${hit.record.record_id} trust=${hit.record.provenance.trust} score=${hit.score.toFixed(3)}] ${hit.record.content}`);
|
|
2150
|
-
}
|
|
2151
|
-
}
|
|
2152
|
-
if (lines.length > 0) {
|
|
2153
|
-
await this.commitKernelApply(runtime, this.pendingObservations, {
|
|
2154
|
-
kind: "add_history_message",
|
|
2155
|
-
message: { role: "user", content: lines.join("\n") },
|
|
2156
|
-
});
|
|
2152
|
+
seen.add(hit.record.record_id);
|
|
2153
|
+
hits.push(hit);
|
|
2157
2154
|
}
|
|
2158
|
-
await this.recordHostMemoryRecall(recalled);
|
|
2159
2155
|
}
|
|
2160
|
-
|
|
2161
|
-
}
|
|
2162
|
-
async archiveSemanticPageOut(archived, action) {
|
|
2163
|
-
if (!this.opts.memoryStore || !this.opts.agentId || !this.opts.memoryScope)
|
|
2164
|
-
return;
|
|
2165
|
-
try {
|
|
2166
|
-
const summary = this.opts.memorySummarizer
|
|
2167
|
-
? await this.opts.memorySummarizer.summarize(archived, { action })
|
|
2168
|
-
: await summarizeForLongTermMemory(this.opts.memoryProvider ?? this.opts.provider, archived, this.opts.memorySystemPrompt);
|
|
2169
|
-
const now = Date.now();
|
|
2170
|
-
const name = `page-out-${now}`;
|
|
2171
|
-
await this.writeMemory({
|
|
2172
|
-
record_id: `${this.opts.memoryScope.tenant_id}:${this.opts.memoryScope.namespace}:project:${name}`,
|
|
2173
|
-
scope: this.opts.memoryScope, name, kind: "project", content: summary,
|
|
2174
|
-
description: `auto summary of ${action ?? "compaction"} archive`,
|
|
2175
|
-
provenance: { author: "extraction", trust: "untrusted", evidence_refs: [] },
|
|
2176
|
-
created_at: now, updated_at: now, recall_count: 0, confidence: 0.6, links: [], pinned: false,
|
|
2177
|
-
}, this.currentSessionId ?? undefined);
|
|
2178
|
-
}
|
|
2179
|
-
catch {
|
|
2180
|
-
// non-fatal
|
|
2181
|
-
}
|
|
2182
|
-
}
|
|
2183
|
-
}
|
|
2184
|
-
async function summarizeForLongTermMemory(provider, archived, systemPrompt) {
|
|
2185
|
-
const transcript = archived
|
|
2186
|
-
.map(m => `${m.role}: ${m.content}`)
|
|
2187
|
-
.join("\n");
|
|
2188
|
-
const context = {
|
|
2189
|
-
systemText: [
|
|
2190
|
-
systemPrompt,
|
|
2191
|
-
"Summarize the following conversation for long-term memory. Preserve key facts, decisions, and open questions.",
|
|
2192
|
-
].filter(Boolean).join("\n\n"),
|
|
2193
|
-
turns: [{ role: "user", content: transcript, toolCalls: [] }],
|
|
2194
|
-
};
|
|
2195
|
-
let text = "";
|
|
2196
|
-
const state = provider.createRunState?.();
|
|
2197
|
-
for await (const evt of provider.stream(context, [], undefined, state)) {
|
|
2198
|
-
if (evt.type === "text_delta")
|
|
2199
|
-
text += evt.delta;
|
|
2156
|
+
return hits;
|
|
2200
2157
|
}
|
|
2201
|
-
return text.trim() || transcript.slice(0, 2000);
|
|
2202
2158
|
}
|
|
2203
2159
|
function isMidRun(events) {
|
|
2204
2160
|
return events.length > 0 && !events.some(e => e.event.kind === "run_terminal");
|