@goah/cli 0.13.3 → 0.13.5
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/{chunk-7E7V6OIU.js → chunk-24NAHA3D.js} +16 -6
- package/dist/{chunk-YH6YJ2IB.js → chunk-CDELLMIJ.js} +37 -10
- package/dist/{chunk-D2DVAH37.js → chunk-J32EKOQ4.js} +1 -1
- package/dist/{chunk-KJ4HJCTK.js → chunk-ORAANUAR.js} +18 -25
- package/dist/{chunk-QBD6EJ2Z.js → chunk-RDUUXBZ2.js} +114 -51
- package/dist/cli.js +38 -18
- package/dist/console/assets/{index-B1vGMXKr.js → index-DYdJZskp.js} +5 -5
- package/dist/console/assets/{index-B1vGMXKr.js.map → index-DYdJZskp.js.map} +1 -1
- package/dist/console/index.html +1 -1
- package/dist/{dist-KNR2XL6J.js → dist-EYYNPOYG.js} +1 -1
- package/dist/execution.d.ts +29 -6
- package/dist/faux-runner-worker.js +13 -6
- package/dist/index.d.ts +29 -6
- package/dist/index.js +5 -5
- package/dist/pi-worker.js +59 -17
- package/dist/runner-pi.d.ts +26 -9
- package/dist/runner-pi.js +1 -1
- package/dist/{runner-registry-GD4BYCQC.js → runner-registry-XCGUS2P3.js} +2 -2
- package/dist/sqlite.d.ts +4 -2
- package/dist/sqlite.js +1 -1
- package/dist/supervisor.d.ts +27 -5
- package/dist/supervisor.js +1 -1
- package/dist/testkit.d.ts +26 -7
- package/dist/testkit.js +5 -1
- package/package.json +1 -1
package/dist/console/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta name="theme-color" content="#f7f7f4" />
|
|
7
7
|
<title>Goah Console</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DYdJZskp.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-3sYrDMmt.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/dist/execution.d.ts
CHANGED
|
@@ -304,6 +304,7 @@ type HandoffValidationResult = {
|
|
|
304
304
|
token: string;
|
|
305
305
|
goalId: string;
|
|
306
306
|
goalRevision: number;
|
|
307
|
+
messageItemId: string;
|
|
307
308
|
} | {
|
|
308
309
|
accepted: false;
|
|
309
310
|
fatal: boolean;
|
|
@@ -312,6 +313,7 @@ type HandoffValidationResult = {
|
|
|
312
313
|
};
|
|
313
314
|
interface HandoffValidationRequest {
|
|
314
315
|
handoff: AgentHandoff;
|
|
316
|
+
candidateMessageId: string;
|
|
315
317
|
candidateMessage: string;
|
|
316
318
|
}
|
|
317
319
|
interface TurnOutput {
|
|
@@ -326,6 +328,28 @@ interface RunnerTraceEvent {
|
|
|
326
328
|
type: string;
|
|
327
329
|
data: JsonValue;
|
|
328
330
|
}
|
|
331
|
+
type AssistantLiveDelta = {
|
|
332
|
+
type: "start" | "text_start" | "text_end" | "thinking_start" | "thinking_end" | "toolcall_start" | "toolcall_end";
|
|
333
|
+
contentIndex?: number;
|
|
334
|
+
} | {
|
|
335
|
+
type: "text_delta" | "thinking_delta" | "toolcall_delta";
|
|
336
|
+
contentIndex: number;
|
|
337
|
+
delta: string;
|
|
338
|
+
};
|
|
339
|
+
interface RunnerLiveEvent {
|
|
340
|
+
type: "message.assistant.delta";
|
|
341
|
+
data: {
|
|
342
|
+
messageId: string;
|
|
343
|
+
delta: AssistantLiveDelta;
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
interface TurnLiveSnapshot {
|
|
347
|
+
revision: number;
|
|
348
|
+
messageId: string;
|
|
349
|
+
text: string;
|
|
350
|
+
thinking: string;
|
|
351
|
+
thinkingActive: boolean;
|
|
352
|
+
}
|
|
329
353
|
type AgentCapability = "ledger.search" | "mail.send" | "schedule.set" | "goal.put" | "team.list" | "goal.get" | "goal.create" | "goal.work" | "goal.delegate" | "goal.reassign" | "goal.revise" | "goal.pause" | "goal.resume" | "goal.complete" | "human.request" | "work_record.list" | "work_record.read" | "work_record.history" | "work_record.diff" | "work_record.search" | "work_record.update" | "memory.append";
|
|
330
354
|
type RunnerControlMethod = "goal.handoff.validate";
|
|
331
355
|
type RunnerRpcMethod = AgentCapability | RunnerControlMethod;
|
|
@@ -418,9 +442,6 @@ interface TurnContext {
|
|
|
418
442
|
activeGoal: GoalSnapshot | null;
|
|
419
443
|
goalCommitment: GoalCommitment | null;
|
|
420
444
|
}
|
|
421
|
-
interface AssistantResponse {
|
|
422
|
-
content: string;
|
|
423
|
-
}
|
|
424
445
|
/** Canonical user-visible assistant prose. Raw provider events remain unchanged. */
|
|
425
446
|
declare function normalizeAssistantText(text: string): string;
|
|
426
447
|
interface RunRequest {
|
|
@@ -432,11 +453,12 @@ interface RunRequest {
|
|
|
432
453
|
context: JsonValue;
|
|
433
454
|
now(): string;
|
|
434
455
|
emit(event: RunnerTraceEvent): void;
|
|
456
|
+
emitLive?(event: RunnerLiveEvent): void;
|
|
435
457
|
rpc?(method: RunnerRpcMethod, params: JsonValue): Promise<JsonValue>;
|
|
436
458
|
}
|
|
437
459
|
type RunnerCandidateResult = {
|
|
438
460
|
outcome: "completed";
|
|
439
|
-
|
|
461
|
+
finalMessageId: string;
|
|
440
462
|
handoff?: TurnOutput;
|
|
441
463
|
} | {
|
|
442
464
|
outcome: "abnormal";
|
|
@@ -514,7 +536,8 @@ interface Ledger extends EventStore {
|
|
|
514
536
|
renewTurnLease(id: string, leaseToken: string, leaseUntil: string, now: string): TurnSnapshot;
|
|
515
537
|
appendTurnEvent(input: EventInput, leaseToken: string): EventRecord;
|
|
516
538
|
repairTurnAttempt(id: string, reason: string, now: string, actor: string): TurnItemSnapshot[];
|
|
517
|
-
finishTurn(id: string, status: "
|
|
539
|
+
finishTurn(id: string, status: "failed" | "interrupted", error: JsonValue, now: string, actor: string): TurnSnapshot;
|
|
540
|
+
commitTurnResponse(id: string, responseItemId: string, now: string, actor: string, mailIds?: string[]): TurnSnapshot;
|
|
518
541
|
releaseTurnProcess(id: string, actor: string): TurnSnapshot;
|
|
519
542
|
putMail(mail: MailSnapshot, actor: string, wakeId?: string): EventRecord;
|
|
520
543
|
putMails(mail: MailSnapshot[], actor: string, wakeId?: string): EventRecord[];
|
|
@@ -554,4 +577,4 @@ declare function assertTurnOutput(value: TurnOutput): void;
|
|
|
554
577
|
declare function assertGoalSnapshot(value: GoalSnapshot): void;
|
|
555
578
|
|
|
556
579
|
export { assertAgentHandoff, assertGoalSnapshot, assertGoalTransition, assertHandoff, assertTurnOutput, assertWakeTransition, goalAutomaticTarget, goalCommitment, goalRoute, humanInboxRoute, humanRequestRoute, noGoalCommitment, normalizeAssistantText, specialistAutomaticTarget, specialistInboxRoute };
|
|
557
|
-
export type { AgentCapability, AgentHandoff, AgentProfile, AgentRole,
|
|
580
|
+
export type { AgentCapability, AgentHandoff, AgentProfile, AgentRole, AssistantLiveDelta, AutomaticTarget, CommittedTurnOutput, DelegationRequest, DelegationResult, GoalChangeAuthority, GoalChangeMetadata, GoalChangeOperation, GoalChangedData, GoalCommitment, GoalCompletionRequest, GoalHandoff, GoalOutcome, GoalPhase, GoalSnapshot, Handoff, HandoffCommit, HandoffValidationIssue, HandoffValidationRequest, HandoffValidationResult, HumanTurnAdmissionRequest, HumanTurnAdmissionResult, Ledger, MailLevel, MailRoute, MailSnapshot, ReassignmentRequest, ReassignmentResult, RunRequest, Runner, RunnerCandidateResult, RunnerChoice, RunnerCommandResult, RunnerConfigurator, RunnerControlMethod, RunnerDiagnostic, RunnerHandle, RunnerLiveEvent, RunnerManifest, RunnerProfile, RunnerRpcMethod, RunnerSetupInteraction, RunnerSetupProgress, RunnerSetupTransaction, RunnerTraceEvent, ScheduleSnapshot, ScheduleStatus, SpecialistRole, TeamMemberMotion, TeamMemberView, ThreadSnapshot, TurnContext, TurnItemSnapshot, TurnItemStatus, TurnItemType, TurnLiveSnapshot, TurnOutput, TurnSnapshot, TurnStatus, TurnTrigger, TurnTriggerKind, WakeSnapshot, WakeStatus, WakeTriggerSnapshot, WakeTriggerStatus, WorkRecordDiff, WorkRecordSnapshot, WorkRecordUpdateRequest };
|
|
@@ -2,7 +2,7 @@ import { createRequire as __goahCreateRequire } from "node:module";
|
|
|
2
2
|
const require = __goahCreateRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
4
|
runProcessWorker
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-24NAHA3D.js";
|
|
6
6
|
import "./chunk-6M3OOCKO.js";
|
|
7
7
|
import "./chunk-K26BVR6O.js";
|
|
8
8
|
import "./chunk-IIJQ3DW4.js";
|
|
@@ -32,6 +32,7 @@ await runProcessWorker(async (request, emit, rpc) => {
|
|
|
32
32
|
const steps = triggerSteps ?? byAgent[request.agent] ?? JSON.parse(process.env.GOAH_FAUX_STEPS ?? "[]");
|
|
33
33
|
let goalCommitment = request.turn?.goalCommitment;
|
|
34
34
|
let recordUpdated = false;
|
|
35
|
+
let messageSequence = 0;
|
|
35
36
|
for (const step of steps) {
|
|
36
37
|
if (step.write) {
|
|
37
38
|
const path = join(process.cwd(), step.write.path);
|
|
@@ -54,8 +55,11 @@ await runProcessWorker(async (request, emit, rpc) => {
|
|
|
54
55
|
await new Promise((resolve) => setTimeout(resolve, step.delayMs));
|
|
55
56
|
if (step.hang)
|
|
56
57
|
await new Promise(() => void 0);
|
|
57
|
-
if (step.response !== void 0)
|
|
58
|
-
|
|
58
|
+
if (step.response !== void 0) {
|
|
59
|
+
const finalMessageId = `faux:${request.execution.id}:attempt:${request.execution.attempt}:message:${++messageSequence}`;
|
|
60
|
+
emit({ type: "message.assistant.completed", data: { message: { id: finalMessageId, role: "assistant", content: [{ type: "text", text: step.response }] }, commitState: "committed" } });
|
|
61
|
+
return { outcome: "completed", finalMessageId };
|
|
62
|
+
}
|
|
59
63
|
if (step.handoff) {
|
|
60
64
|
const draft = step.handoff;
|
|
61
65
|
if (goalCommitment && !recordUpdated) {
|
|
@@ -64,16 +68,19 @@ await runProcessWorker(async (request, emit, rpc) => {
|
|
|
64
68
|
const evidence = sourceSeqs(request.context);
|
|
65
69
|
await rpc("work_record.update", { expectedRevision: Number(record.recordRevision ?? 0), content: handoffRecord(draft.handoff, request.execution.id), reason: "record faux Goal progress", evidence: evidence.length ? [Math.max(...evidence)] : [] });
|
|
66
70
|
}
|
|
67
|
-
const
|
|
68
|
-
|
|
71
|
+
const messageItemId = `faux:${request.execution.id}:attempt:${request.execution.attempt}:message:${++messageSequence}`;
|
|
72
|
+
const validation = await rpc("goal.handoff.validate", { handoff: draft.handoff, candidateMessageId: messageItemId, candidateMessage: draft.response.content });
|
|
73
|
+
emit({ type: "message.assistant.completed", data: { message: { id: messageItemId, role: "assistant", content: [{ type: "text", text: draft.response.content }], stopReason: "toolUse" }, commitState: "provisional" } });
|
|
69
74
|
if (!validation.accepted) {
|
|
70
75
|
emit({ type: "runner.handoff_rejected", data: { attemptId: validation.attemptId, issues: validation.issues } });
|
|
71
76
|
if (validation.fatal)
|
|
72
77
|
return { outcome: "abnormal", reason: validation.issues.map((issue) => issue.message).join("; ") };
|
|
73
78
|
continue;
|
|
74
79
|
}
|
|
80
|
+
if (validation.messageItemId !== messageItemId)
|
|
81
|
+
return { outcome: "abnormal", reason: "Handoff validation returned a different assistant message identity" };
|
|
75
82
|
const output = { validationAttemptId: validation.attemptId, validationToken: validation.token, handoff: draft.handoff };
|
|
76
|
-
return { outcome: "completed",
|
|
83
|
+
return { outcome: "completed", finalMessageId: messageItemId, handoff: output };
|
|
77
84
|
}
|
|
78
85
|
}
|
|
79
86
|
return { outcome: "abnormal", reason: "faux worker stopped without handoff" };
|
package/dist/index.d.ts
CHANGED
|
@@ -310,6 +310,28 @@ interface RunnerTraceEvent {
|
|
|
310
310
|
type: string;
|
|
311
311
|
data: JsonValue;
|
|
312
312
|
}
|
|
313
|
+
type AssistantLiveDelta = {
|
|
314
|
+
type: "start" | "text_start" | "text_end" | "thinking_start" | "thinking_end" | "toolcall_start" | "toolcall_end";
|
|
315
|
+
contentIndex?: number;
|
|
316
|
+
} | {
|
|
317
|
+
type: "text_delta" | "thinking_delta" | "toolcall_delta";
|
|
318
|
+
contentIndex: number;
|
|
319
|
+
delta: string;
|
|
320
|
+
};
|
|
321
|
+
interface RunnerLiveEvent {
|
|
322
|
+
type: "message.assistant.delta";
|
|
323
|
+
data: {
|
|
324
|
+
messageId: string;
|
|
325
|
+
delta: AssistantLiveDelta;
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
interface TurnLiveSnapshot {
|
|
329
|
+
revision: number;
|
|
330
|
+
messageId: string;
|
|
331
|
+
text: string;
|
|
332
|
+
thinking: string;
|
|
333
|
+
thinkingActive: boolean;
|
|
334
|
+
}
|
|
313
335
|
type AgentCapability = "ledger.search" | "mail.send" | "schedule.set" | "goal.put" | "team.list" | "goal.get" | "goal.create" | "goal.work" | "goal.delegate" | "goal.reassign" | "goal.revise" | "goal.pause" | "goal.resume" | "goal.complete" | "human.request" | "work_record.list" | "work_record.read" | "work_record.history" | "work_record.diff" | "work_record.search" | "work_record.update" | "memory.append";
|
|
314
336
|
type RunnerControlMethod = "goal.handoff.validate";
|
|
315
337
|
type RunnerRpcMethod = AgentCapability | RunnerControlMethod;
|
|
@@ -337,9 +359,6 @@ interface TurnContext {
|
|
|
337
359
|
activeGoal: GoalSnapshot | null;
|
|
338
360
|
goalCommitment: GoalCommitment | null;
|
|
339
361
|
}
|
|
340
|
-
interface AssistantResponse {
|
|
341
|
-
content: string;
|
|
342
|
-
}
|
|
343
362
|
interface RunRequest {
|
|
344
363
|
agent: string;
|
|
345
364
|
execution: TurnSnapshot;
|
|
@@ -349,11 +368,12 @@ interface RunRequest {
|
|
|
349
368
|
context: JsonValue;
|
|
350
369
|
now(): string;
|
|
351
370
|
emit(event: RunnerTraceEvent): void;
|
|
371
|
+
emitLive?(event: RunnerLiveEvent): void;
|
|
352
372
|
rpc?(method: RunnerRpcMethod, params: JsonValue): Promise<JsonValue>;
|
|
353
373
|
}
|
|
354
374
|
type RunnerCandidateResult = {
|
|
355
375
|
outcome: "completed";
|
|
356
|
-
|
|
376
|
+
finalMessageId: string;
|
|
357
377
|
handoff?: TurnOutput;
|
|
358
378
|
} | {
|
|
359
379
|
outcome: "abnormal";
|
|
@@ -431,7 +451,8 @@ interface Ledger extends EventStore {
|
|
|
431
451
|
renewTurnLease(id: string, leaseToken: string, leaseUntil: string, now: string): TurnSnapshot;
|
|
432
452
|
appendTurnEvent(input: EventInput, leaseToken: string): EventRecord;
|
|
433
453
|
repairTurnAttempt(id: string, reason: string, now: string, actor: string): TurnItemSnapshot[];
|
|
434
|
-
finishTurn(id: string, status: "
|
|
454
|
+
finishTurn(id: string, status: "failed" | "interrupted", error: JsonValue, now: string, actor: string): TurnSnapshot;
|
|
455
|
+
commitTurnResponse(id: string, responseItemId: string, now: string, actor: string, mailIds?: string[]): TurnSnapshot;
|
|
435
456
|
releaseTurnProcess(id: string, actor: string): TurnSnapshot;
|
|
436
457
|
putMail(mail: MailSnapshot, actor: string, wakeId?: string): EventRecord;
|
|
437
458
|
putMails(mail: MailSnapshot[], actor: string, wakeId?: string): EventRecord[];
|
|
@@ -518,7 +539,8 @@ declare class SqliteLedger implements Ledger {
|
|
|
518
539
|
renewTurnLease(id: string, leaseToken: string, leaseUntil: string, now: string): TurnSnapshot;
|
|
519
540
|
appendTurnEvent(input: EventInput, leaseToken: string): EventRecord;
|
|
520
541
|
repairTurnAttempt(id: string, reason: string, now: string, actor: string): TurnItemSnapshot[];
|
|
521
|
-
finishTurn(id: string, status: "
|
|
542
|
+
finishTurn(id: string, status: "failed" | "interrupted", error: JsonValue, now: string, actor: string): TurnSnapshot;
|
|
543
|
+
commitTurnResponse(id: string, responseItemId: string, now: string, actor: string, mailIds?: string[]): TurnSnapshot;
|
|
522
544
|
releaseTurnProcess(id: string, actor: string): TurnSnapshot;
|
|
523
545
|
putMail(mail: MailSnapshot, actor: string, wakeId?: string): EventRecord;
|
|
524
546
|
putMails(mails: MailSnapshot[], actor: string, wakeId?: string): EventRecord[];
|
|
@@ -598,6 +620,7 @@ declare class Supervisor {
|
|
|
598
620
|
goal: GoalSnapshot;
|
|
599
621
|
}>;
|
|
600
622
|
interruptTurn(turnId: string): Promise<TurnSnapshot>;
|
|
623
|
+
liveTurnSnapshot(turnId: string, afterRevision?: number): TurnLiveSnapshot | null;
|
|
601
624
|
sendToCeo(body: JsonValue): Promise<{
|
|
602
625
|
threadId: string;
|
|
603
626
|
turnId: string;
|
package/dist/index.js
CHANGED
|
@@ -31,11 +31,11 @@ import {
|
|
|
31
31
|
updateWorkspaceRunnerProfile,
|
|
32
32
|
writeDefaultConfig,
|
|
33
33
|
writeDefaultRunnerProfile
|
|
34
|
-
} from "./chunk-
|
|
35
|
-
import "./chunk-
|
|
36
|
-
import "./chunk-
|
|
37
|
-
import "./chunk-
|
|
38
|
-
import "./chunk-
|
|
34
|
+
} from "./chunk-ORAANUAR.js";
|
|
35
|
+
import "./chunk-J32EKOQ4.js";
|
|
36
|
+
import "./chunk-CDELLMIJ.js";
|
|
37
|
+
import "./chunk-RDUUXBZ2.js";
|
|
38
|
+
import "./chunk-24NAHA3D.js";
|
|
39
39
|
import "./chunk-6M3OOCKO.js";
|
|
40
40
|
import "./chunk-K26BVR6O.js";
|
|
41
41
|
import "./chunk-IIJQ3DW4.js";
|
package/dist/pi-worker.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-XALZLRYK.js";
|
|
6
6
|
import {
|
|
7
7
|
runProcessWorker
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-24NAHA3D.js";
|
|
9
9
|
import {
|
|
10
10
|
createPiModel,
|
|
11
11
|
fauxAssistantMessage,
|
|
@@ -35,6 +35,9 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
35
35
|
import { delimiter, dirname, join, resolve, sep } from "node:path";
|
|
36
36
|
import { homedir, tmpdir } from "node:os";
|
|
37
37
|
import { fileURLToPath } from "node:url";
|
|
38
|
+
var GOAL_TURN_POLICY = `A Goal commitment starts a sustained work session, not a short status round. Continue working while any safe, useful action can be executed now with current tools and authority. Use the Work Record as a durable checkpoint whenever the semantic state changes; updating it does not end the Turn. Planning, partial progress, decomposition, or scheduling a future Wake are not by themselves reasons to stop. Before Handoff, ask whether another useful action can be completed without new authority, unavailable data, another Agent's result, or the passage of time; if yes, do it now.
|
|
39
|
+
|
|
40
|
+
Call handoff exactly once, only at a genuine control boundary: the current actionable frontier is exhausted after meaningful work, an explicit external wait is required, a real blocker prevents safe progress, or completion evidence is ready for review. Use outcome progress only for the first case, waiting only for the second, blocked only for the third, and completion_proposed only for the fourth. Write a concise human-readable assistant message describing what happened, and keep Handoff machine-readable with only outcome and evidence. Treat the supplied context as authoritative.`;
|
|
38
41
|
function compactMessages(messages, maxRecent = 8) {
|
|
39
42
|
if (messages.length <= maxRecent + 1)
|
|
40
43
|
return messages;
|
|
@@ -48,7 +51,7 @@ ${summary}`, timestamp: Date.now() },
|
|
|
48
51
|
];
|
|
49
52
|
}
|
|
50
53
|
async function runPiWorker() {
|
|
51
|
-
await runProcessWorker(async (request, emit, rpc, controls) => {
|
|
54
|
+
await runProcessWorker(async (request, emit, rpc, controls, emitLive) => {
|
|
52
55
|
const contextRecord = typeof request.context === "object" && request.context !== null && !Array.isArray(request.context) ? request.context : {};
|
|
53
56
|
const legacyRequest = request.turn === void 0;
|
|
54
57
|
const binding = request.turn?.goalCommitment;
|
|
@@ -100,8 +103,10 @@ Follow the current Goal and explicit tools.
|
|
|
100
103
|
`;
|
|
101
104
|
const finalResponse = fauxAssistantMessage([fauxText(String(handoff.message ?? `Goal work recorded with outcome ${outcome}.`)), fauxToolCall("handoff", { outcome, evidence: handoffEvidence })], { stopReason: "toolUse" });
|
|
102
105
|
const recordResponse = fauxAssistantMessage(fauxToolCall("work_record_update", { expectedRevision: Number(current.recordRevision ?? 0), content: record, reason: "record faux Goal progress", evidence: evidence.length ? [Math.max(...evidence)] : [] }), { stopReason: "toolUse" });
|
|
106
|
+
const narratedScheduleResponse = fauxAssistantMessage([fauxText(String(handoff.message ?? "Work Record updated; the next wake is scheduled.")), fauxToolCall("schedule_wake", { at: new Date(Date.parse(request.execution.startedAt) + 6e4).toISOString(), reason: "continue Goal work" })], { stopReason: "toolUse" });
|
|
107
|
+
const toolOnlyHandoff = fauxAssistantMessage(fauxToolCall("handoff", { outcome, evidence: handoffEvidence }), { stopReason: "toolUse" });
|
|
103
108
|
const fatalBatch = fauxAssistantMessage([fauxText("Stale completion attempt."), fauxToolCall("handoff", { outcome, evidence: handoffEvidence }), fauxToolCall("write", { path: "fatal.txt", content: "must not be written" })], { stopReason: "toolUse" });
|
|
104
|
-
faux.setResponses(process.env.GOAH_PI_FAUX_FATAL_BATCH === "1" ? [fatalBatch] : process.env.GOAH_PI_FAUX_HANDOFF_REPAIR === "1" ? [fauxAssistantMessage([fauxText("Premature completion attempt."), fauxToolCall("handoff", { outcome, evidence: handoffEvidence })], { stopReason: "toolUse" }), recordResponse, finalResponse] : [recordResponse, finalResponse]);
|
|
109
|
+
faux.setResponses(process.env.GOAH_PI_FAUX_FATAL_BATCH === "1" ? [fatalBatch] : process.env.GOAH_PI_FAUX_HANDOFF_REPAIR === "1" ? [fauxAssistantMessage([fauxText("Premature completion attempt."), fauxToolCall("handoff", { outcome, evidence: handoffEvidence })], { stopReason: "toolUse" }), recordResponse, finalResponse] : process.env.GOAH_PI_FAUX_TOOL_ONLY_HANDOFF === "1" ? [recordResponse, narratedScheduleResponse, toolOnlyHandoff] : [recordResponse, finalResponse]);
|
|
105
110
|
} else if (!goalState.bound) {
|
|
106
111
|
faux.setResponses([fauxAssistantMessage([fauxText(process.env.GOAH_PI_FAUX_RESPONSE ?? "Hello from Goah.")])]);
|
|
107
112
|
} else {
|
|
@@ -113,10 +118,11 @@ Follow the current Goal and explicit tools.
|
|
|
113
118
|
let output = null;
|
|
114
119
|
let acceptedHandoff = null;
|
|
115
120
|
let revokedReason = "";
|
|
116
|
-
let
|
|
121
|
+
let lastReadableMessage = null;
|
|
117
122
|
let responseFailure = "";
|
|
118
123
|
let compactions = 0;
|
|
119
124
|
let messageCounter = 0;
|
|
125
|
+
let activeAssistantMessageId = null;
|
|
120
126
|
const messageIds = /* @__PURE__ */ new WeakMap();
|
|
121
127
|
const emittedUsers = /* @__PURE__ */ new Set();
|
|
122
128
|
const idFor = (message) => {
|
|
@@ -125,7 +131,7 @@ Follow the current Goal and explicit tools.
|
|
|
125
131
|
const existing = messageIds.get(message);
|
|
126
132
|
if (existing)
|
|
127
133
|
return existing;
|
|
128
|
-
const id =
|
|
134
|
+
const id = `${request.execution.id}:attempt:${request.execution.attempt}:message:${++messageCounter}`;
|
|
129
135
|
messageIds.set(message, id);
|
|
130
136
|
return id;
|
|
131
137
|
};
|
|
@@ -145,8 +151,11 @@ Follow the current Goal and explicit tools.
|
|
|
145
151
|
const sourceSeqs = Array.isArray(contextRecord.sourceSeqs) ? contextRecord.sourceSeqs.filter((value) => Number.isInteger(value)) : [];
|
|
146
152
|
const basePrompt = process.env.GOAH_PI_SYSTEM_PROMPT ?? suppliedPrompt ?? (request.turn?.trigger.kind === "user_message" ? "You are Goah's primary Agent. Respond naturally to the Human." : `You are Goah Agent ${request.agent}. Inspect the supplied context and respond appropriately.`);
|
|
147
153
|
const systemPrompt = goalState.bound ? `${basePrompt}
|
|
148
|
-
|
|
149
|
-
|
|
154
|
+
|
|
155
|
+
${GOAL_TURN_POLICY}` : request.turn?.trigger.kind === "user_message" ? `${basePrompt}
|
|
156
|
+
The active Goal, when supplied, is context rather than an assignment. Finish with an ordinary response unless a Goal tool establishes a commitment during this Turn. If a Goal commitment is established, follow this policy for the rest of the Turn:
|
|
157
|
+
|
|
158
|
+
${GOAL_TURN_POLICY}` : `${basePrompt}
|
|
150
159
|
This Turn has no Goal commitment. Finish with an ordinary response and do not call handoff. Treat the supplied context as authoritative.`;
|
|
151
160
|
const agent = new Agent({
|
|
152
161
|
initialState: {
|
|
@@ -196,10 +205,16 @@ This Turn has no Goal commitment. Finish with an ordinary response and do not ca
|
|
|
196
205
|
acceptedHandoff = null;
|
|
197
206
|
output = null;
|
|
198
207
|
const handoff = args;
|
|
208
|
+
const currentText = assistantResponseText(assistantMessage);
|
|
209
|
+
const candidate = currentText ? activeAssistantMessageId ? { id: activeAssistantMessageId, text: currentText } : lastReadableMessage?.text === currentText ? lastReadableMessage : { id: idFor(assistantMessage), text: currentText } : lastReadableMessage;
|
|
199
210
|
try {
|
|
200
|
-
const result = await rpc("goal.handoff.validate", { handoff, candidateMessage:
|
|
211
|
+
const result = await rpc("goal.handoff.validate", { handoff, candidateMessageId: candidate?.id ?? "", candidateMessage: candidate?.text ?? "" });
|
|
201
212
|
if (result.accepted) {
|
|
202
|
-
|
|
213
|
+
if (!candidate || result.messageItemId !== candidate.id) {
|
|
214
|
+
revokedReason = "Handoff validation returned a different assistant message identity";
|
|
215
|
+
return { block: true, reason: revokedReason, terminate: true };
|
|
216
|
+
}
|
|
217
|
+
acceptedHandoff = { attemptId: result.attemptId, token: result.token, messageItemId: result.messageItemId, handoff };
|
|
203
218
|
return;
|
|
204
219
|
}
|
|
205
220
|
const reason = result.issues.map((issue) => `- ${issue.message}`).join("\n");
|
|
@@ -225,20 +240,33 @@ ${reason}`, terminate: result.fatal };
|
|
|
225
240
|
agent.subscribe((event) => {
|
|
226
241
|
if (event.type === "turn_start")
|
|
227
242
|
emit({ type: "turn.started", data: {} });
|
|
228
|
-
else if (event.type === "message_start"
|
|
243
|
+
else if (event.type === "message_start") {
|
|
244
|
+
if (event.message.role === "assistant") {
|
|
245
|
+
activeAssistantMessageId = idFor(event.message);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (event.message.role !== "user")
|
|
249
|
+
return;
|
|
229
250
|
const id = idFor(event.message);
|
|
230
251
|
if (!emittedUsers.has(id)) {
|
|
231
252
|
emittedUsers.add(id);
|
|
232
253
|
emit({ type: "message.user", data: { message: transcriptMessage(event.message, id) } });
|
|
233
254
|
}
|
|
234
255
|
} else if (event.type === "message_update") {
|
|
235
|
-
|
|
256
|
+
const delta = minimalLiveDelta(event.assistantMessageEvent);
|
|
257
|
+
if (delta)
|
|
258
|
+
emitLive({ type: "message.assistant.delta", data: { messageId: activeAssistantMessageId ?? idFor(event.message), delta } });
|
|
236
259
|
} else if (event.type === "message_end" && event.message.role === "assistant") {
|
|
237
|
-
|
|
260
|
+
const messageId = activeAssistantMessageId ?? idFor(event.message);
|
|
261
|
+
messageIds.set(event.message, messageId);
|
|
262
|
+
const text = assistantResponseText(event.message);
|
|
263
|
+
if (text)
|
|
264
|
+
lastReadableMessage = { id: messageId, text };
|
|
238
265
|
if ((event.message.stopReason === "error" || event.message.stopReason === "aborted") && event.message.errorMessage)
|
|
239
266
|
responseFailure = event.message.errorMessage;
|
|
240
267
|
const handoffIntent = hasAgentToolCall(event.message, "handoff");
|
|
241
|
-
emit({ type: "message.assistant.completed", data: { message: transcriptMessage(event.message,
|
|
268
|
+
emit({ type: "message.assistant.completed", data: { message: transcriptMessage(event.message, messageId), commitState: handoffIntent ? "provisional" : "committed" } });
|
|
269
|
+
activeAssistantMessageId = null;
|
|
242
270
|
} else if (event.type === "tool_execution_start")
|
|
243
271
|
emit({ type: "tool.called", data: { callId: event.toolCallId, name: event.toolName, arguments: JSON.parse(JSON.stringify(event.args)) } });
|
|
244
272
|
else if (event.type === "tool_execution_end")
|
|
@@ -262,13 +290,17 @@ Runner root: ${root}. Manage local files directly when the goal requires them.`)
|
|
|
262
290
|
}
|
|
263
291
|
if (revokedReason)
|
|
264
292
|
return { outcome: "abnormal", reason: revokedReason };
|
|
293
|
+
const finalMessage = lastReadableMessage;
|
|
265
294
|
if (!goalState.bound)
|
|
266
|
-
return
|
|
295
|
+
return finalMessage ? { outcome: "completed", finalMessageId: finalMessage.id } : { outcome: "abnormal", reason: responseFailure || "Pi worker exited without a response" };
|
|
267
296
|
if (responseFailure)
|
|
268
297
|
return { outcome: "abnormal", reason: responseFailure };
|
|
269
298
|
if (!output)
|
|
270
299
|
return { outcome: "abnormal", reason: "Pi worker exited without an accepted Handoff" };
|
|
271
|
-
|
|
300
|
+
const finalHandoff = acceptedHandoff;
|
|
301
|
+
if (!finalHandoff)
|
|
302
|
+
return { outcome: "abnormal", reason: "Pi worker exited without an accepted Handoff message" };
|
|
303
|
+
return { outcome: "completed", finalMessageId: finalHandoff.messageItemId, handoff: output };
|
|
272
304
|
});
|
|
273
305
|
}
|
|
274
306
|
function snapshotModelConfig(options) {
|
|
@@ -290,11 +322,20 @@ function transcriptMessage(message, id) {
|
|
|
290
322
|
const role = message.role === "assistant" ? "assistant" : message.role === "user" ? "user" : "tool";
|
|
291
323
|
return { id, role, content: value.content ?? value, ...value.usage !== void 0 ? { usage: value.usage } : {}, ...typeof value.stopReason === "string" ? { stopReason: value.stopReason } : {}, ...typeof value.errorMessage === "string" ? { errorMessage: value.errorMessage } : {} };
|
|
292
324
|
}
|
|
325
|
+
function minimalLiveDelta(event) {
|
|
326
|
+
if (event.type === "start")
|
|
327
|
+
return { type: "start" };
|
|
328
|
+
if (event.type === "text_delta" || event.type === "thinking_delta" || event.type === "toolcall_delta")
|
|
329
|
+
return { type: event.type, contentIndex: event.contentIndex, delta: event.delta };
|
|
330
|
+
if (event.type === "text_start" || event.type === "text_end" || event.type === "thinking_start" || event.type === "thinking_end" || event.type === "toolcall_start" || event.type === "toolcall_end")
|
|
331
|
+
return { type: event.type, contentIndex: event.contentIndex };
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
293
334
|
function createTools(root, handoff, rpc, capabilities, goalState, protectedPaths = []) {
|
|
294
335
|
const handoffTool = {
|
|
295
336
|
name: "handoff",
|
|
296
337
|
label: "Handoff",
|
|
297
|
-
description: "
|
|
338
|
+
description: "End the current Goal Turn at a genuine control boundary. Do not call while another safe and useful action can be completed now. Planning, partial progress, a Work Record update, or a scheduled Wake does not by itself justify Handoff.",
|
|
298
339
|
parameters: typebox_exports.Object({
|
|
299
340
|
outcome: typebox_exports.Union([typebox_exports.Literal("progress"), typebox_exports.Literal("waiting"), typebox_exports.Literal("blocked"), typebox_exports.Literal("completion_proposed")]),
|
|
300
341
|
evidence: typebox_exports.Array(typebox_exports.Number())
|
|
@@ -488,7 +529,7 @@ function createRpcTools(rpc, allowed, onResult) {
|
|
|
488
529
|
["ledger.search", tool("ledger_search", "Search durable ledger facts.", "ledger.search", typebox_exports.Object({ query: typebox_exports.String(), limit: typebox_exports.Optional(typebox_exports.Number()) }))],
|
|
489
530
|
["memory.append", tool("memory_append", "Append a durable working-memory note that is injected into your future wakes. Record procedural knowledge, active hypotheses, and abandoned approaches with the reason; keep notes concise.", "memory.append", typebox_exports.Object({ note: typebox_exports.String() }))],
|
|
490
531
|
["mail.send", tool("send_mail", "Send durable Mail to another Goal owner. goalId is required and routes the Mail into that owner's next committed Turn. Human communication must use request_human.", "mail.send", typebox_exports.Object({ to: typebox_exports.String(), goalId: typebox_exports.String(), level: typebox_exports.Union([typebox_exports.Literal("fyi"), typebox_exports.Literal("decision"), typebox_exports.Literal("emergency")]), body: typebox_exports.Any() }))],
|
|
491
|
-
["schedule.set", tool("schedule_wake", "Schedule
|
|
532
|
+
["schedule.set", tool("schedule_wake", "Schedule genuinely time-dependent future observation. Scheduling does not end the current Turn; continue all useful work that can be completed before waiting.", "schedule.set", typebox_exports.Object({ at: typebox_exports.String(), reason: typebox_exports.String() }))],
|
|
492
533
|
["team.list", tool("team_list", "Read the ledger-derived team roster and liveness state.", "team.list", typebox_exports.Object({}))],
|
|
493
534
|
["goal.get", tool("get_goal", "Read the active Goal visible to this Turn. Visibility does not establish a Goal commitment.", "goal.get", typebox_exports.Object({}))],
|
|
494
535
|
["goal.create", tool("create_goal", "Create a Root Goal from durable Human intent and bind this Turn. Do not use for greetings, questions, or routine single-turn work.", "goal.create", typebox_exports.Object({ objective: typebox_exports.String(), id: typebox_exports.Optional(typebox_exports.String()) }))],
|
|
@@ -662,6 +703,7 @@ export {
|
|
|
662
703
|
compactMessages,
|
|
663
704
|
compactMessagesToTokenBudget,
|
|
664
705
|
linuxSandboxArgs,
|
|
706
|
+
minimalLiveDelta,
|
|
665
707
|
resolveContextPolicy,
|
|
666
708
|
runBashCommand,
|
|
667
709
|
runPiWorker,
|
package/dist/runner-pi.d.ts
CHANGED
|
@@ -87,6 +87,7 @@ type HandoffValidationResult = {
|
|
|
87
87
|
token: string;
|
|
88
88
|
goalId: string;
|
|
89
89
|
goalRevision: number;
|
|
90
|
+
messageItemId: string;
|
|
90
91
|
} | {
|
|
91
92
|
accepted: false;
|
|
92
93
|
fatal: boolean;
|
|
@@ -102,6 +103,21 @@ interface RunnerTraceEvent {
|
|
|
102
103
|
type: string;
|
|
103
104
|
data: JsonValue;
|
|
104
105
|
}
|
|
106
|
+
type AssistantLiveDelta = {
|
|
107
|
+
type: "start" | "text_start" | "text_end" | "thinking_start" | "thinking_end" | "toolcall_start" | "toolcall_end";
|
|
108
|
+
contentIndex?: number;
|
|
109
|
+
} | {
|
|
110
|
+
type: "text_delta" | "thinking_delta" | "toolcall_delta";
|
|
111
|
+
contentIndex: number;
|
|
112
|
+
delta: string;
|
|
113
|
+
};
|
|
114
|
+
interface RunnerLiveEvent {
|
|
115
|
+
type: "message.assistant.delta";
|
|
116
|
+
data: {
|
|
117
|
+
messageId: string;
|
|
118
|
+
delta: AssistantLiveDelta;
|
|
119
|
+
};
|
|
120
|
+
}
|
|
105
121
|
type AgentCapability = "ledger.search" | "mail.send" | "schedule.set" | "goal.put" | "team.list" | "goal.get" | "goal.create" | "goal.work" | "goal.delegate" | "goal.reassign" | "goal.revise" | "goal.pause" | "goal.resume" | "goal.complete" | "human.request" | "work_record.list" | "work_record.read" | "work_record.history" | "work_record.diff" | "work_record.search" | "work_record.update" | "memory.append";
|
|
106
122
|
type RunnerControlMethod = "goal.handoff.validate";
|
|
107
123
|
type RunnerRpcMethod = AgentCapability | RunnerControlMethod;
|
|
@@ -181,9 +197,6 @@ interface TurnContext {
|
|
|
181
197
|
activeGoal: GoalSnapshot | null;
|
|
182
198
|
goalCommitment: GoalCommitment | null;
|
|
183
199
|
}
|
|
184
|
-
interface AssistantResponse {
|
|
185
|
-
content: string;
|
|
186
|
-
}
|
|
187
200
|
interface RunRequest {
|
|
188
201
|
agent: string;
|
|
189
202
|
execution: TurnSnapshot;
|
|
@@ -193,11 +206,12 @@ interface RunRequest {
|
|
|
193
206
|
context: JsonValue;
|
|
194
207
|
now(): string;
|
|
195
208
|
emit(event: RunnerTraceEvent): void;
|
|
209
|
+
emitLive?(event: RunnerLiveEvent): void;
|
|
196
210
|
rpc?(method: RunnerRpcMethod, params: JsonValue): Promise<JsonValue>;
|
|
197
211
|
}
|
|
198
212
|
type RunnerCandidateResult = {
|
|
199
213
|
outcome: "completed";
|
|
200
|
-
|
|
214
|
+
finalMessageId: string;
|
|
201
215
|
handoff?: TurnOutput;
|
|
202
216
|
} | {
|
|
203
217
|
outcome: "abnormal";
|
|
@@ -267,14 +281,17 @@ interface EnvSpecSource {
|
|
|
267
281
|
*/
|
|
268
282
|
declare function resolveEnvSpec(spec: Record<string, string> | undefined, source: EnvSpecSource | undefined): Record<string, string>;
|
|
269
283
|
|
|
284
|
+
interface PiAssistantResponse {
|
|
285
|
+
content: string;
|
|
286
|
+
}
|
|
270
287
|
interface PiStep {
|
|
271
288
|
trace?: Array<{
|
|
272
289
|
type: string;
|
|
273
290
|
data: JsonValue;
|
|
274
291
|
}>;
|
|
275
|
-
response?:
|
|
292
|
+
response?: PiAssistantResponse;
|
|
276
293
|
handoff?: {
|
|
277
|
-
response:
|
|
294
|
+
response: PiAssistantResponse;
|
|
278
295
|
handoff: AgentHandoff;
|
|
279
296
|
};
|
|
280
297
|
stopped?: boolean;
|
|
@@ -315,7 +332,7 @@ interface ProcessRunnerOptions {
|
|
|
315
332
|
}
|
|
316
333
|
declare function piWorkerPath(): string;
|
|
317
334
|
declare function verificationWorkerPath(): string;
|
|
318
|
-
type WorkerRequest = Omit<RunRequest, "now" | "emit" | "rpc" | "turn"> & {
|
|
335
|
+
type WorkerRequest = Omit<RunRequest, "now" | "emit" | "emitLive" | "rpc" | "turn"> & {
|
|
319
336
|
turn?: TurnContext;
|
|
320
337
|
runtime?: JsonValue;
|
|
321
338
|
};
|
|
@@ -334,9 +351,9 @@ interface WorkerControls {
|
|
|
334
351
|
type WorkerRun = (request: WorkerRequest, emit: (event: {
|
|
335
352
|
type: string;
|
|
336
353
|
data: JsonValue;
|
|
337
|
-
}) => void, rpc: WorkerRpc, controls: WorkerControls) => Promise<RunnerCandidateResult>;
|
|
354
|
+
}) => void, rpc: WorkerRpc, controls: WorkerControls, emitLive: (event: RunnerLiveEvent) => void) => Promise<RunnerCandidateResult>;
|
|
338
355
|
/** Entry helper for runner executables. It exits when its parent disappears. */
|
|
339
356
|
declare function runProcessWorker(run: WorkerRun): Promise<void>;
|
|
340
357
|
|
|
341
358
|
export { LOCAL_PROVIDERS, PiRunnerAdapter, ProcessRunner, createPiProcessRunner, defaultAuthFile, modelCatalog, piConfig, piEnvironment, piRunnerConfigurator, piWorkerPath, providerCatalog, resolveEnvSpec, runProcessWorker, verificationWorkerPath };
|
|
342
|
-
export type { ModelSummary, PiDriver, PiRunnerConfig, PiRunnerSession, PiStep, ProcessRunnerOptions, ProviderSummary, WorkerControls, WorkerRpc, WorkerRun };
|
|
359
|
+
export type { ModelSummary, PiAssistantResponse, PiDriver, PiRunnerConfig, PiRunnerSession, PiStep, ProcessRunnerOptions, ProviderSummary, WorkerControls, WorkerRpc, WorkerRun };
|
package/dist/runner-pi.js
CHANGED
|
@@ -3,8 +3,8 @@ const require = __goahCreateRequire(import.meta.url);
|
|
|
3
3
|
import {
|
|
4
4
|
runnerManifests,
|
|
5
5
|
runnerPlugin
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-J32EKOQ4.js";
|
|
7
|
+
import "./chunk-24NAHA3D.js";
|
|
8
8
|
import "./chunk-6M3OOCKO.js";
|
|
9
9
|
import "./chunk-K26BVR6O.js";
|
|
10
10
|
import "./chunk-IIJQ3DW4.js";
|
package/dist/sqlite.d.ts
CHANGED
|
@@ -320,7 +320,8 @@ interface Ledger extends EventStore {
|
|
|
320
320
|
renewTurnLease(id: string, leaseToken: string, leaseUntil: string, now: string): TurnSnapshot;
|
|
321
321
|
appendTurnEvent(input: EventInput, leaseToken: string): EventRecord;
|
|
322
322
|
repairTurnAttempt(id: string, reason: string, now: string, actor: string): TurnItemSnapshot[];
|
|
323
|
-
finishTurn(id: string, status: "
|
|
323
|
+
finishTurn(id: string, status: "failed" | "interrupted", error: JsonValue, now: string, actor: string): TurnSnapshot;
|
|
324
|
+
commitTurnResponse(id: string, responseItemId: string, now: string, actor: string, mailIds?: string[]): TurnSnapshot;
|
|
324
325
|
releaseTurnProcess(id: string, actor: string): TurnSnapshot;
|
|
325
326
|
putMail(mail: MailSnapshot, actor: string, wakeId?: string): EventRecord;
|
|
326
327
|
putMails(mail: MailSnapshot[], actor: string, wakeId?: string): EventRecord[];
|
|
@@ -408,7 +409,8 @@ declare class SqliteLedger implements Ledger {
|
|
|
408
409
|
renewTurnLease(id: string, leaseToken: string, leaseUntil: string, now: string): TurnSnapshot;
|
|
409
410
|
appendTurnEvent(input: EventInput, leaseToken: string): EventRecord;
|
|
410
411
|
repairTurnAttempt(id: string, reason: string, now: string, actor: string): TurnItemSnapshot[];
|
|
411
|
-
finishTurn(id: string, status: "
|
|
412
|
+
finishTurn(id: string, status: "failed" | "interrupted", error: JsonValue, now: string, actor: string): TurnSnapshot;
|
|
413
|
+
commitTurnResponse(id: string, responseItemId: string, now: string, actor: string, mailIds?: string[]): TurnSnapshot;
|
|
412
414
|
releaseTurnProcess(id: string, actor: string): TurnSnapshot;
|
|
413
415
|
putMail(mail: MailSnapshot, actor: string, wakeId?: string): EventRecord;
|
|
414
416
|
putMails(mails: MailSnapshot[], actor: string, wakeId?: string): EventRecord[];
|
package/dist/sqlite.js
CHANGED