@springbrand/agent-runtime 0.2.0-alpha.38 → 0.2.0-alpha.40
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/package.json
CHANGED
|
@@ -236,10 +236,10 @@ const IDEMPOTENT_TOOL_NAMES = new Set([
|
|
|
236
236
|
export function piToolRetryPolicy(
|
|
237
237
|
candidate: PiToolCandidate,
|
|
238
238
|
): "idempotent" | "non-idempotent" {
|
|
239
|
-
return IDEMPOTENT_TOOL_NAMES.has(candidate.tool.name) ||
|
|
239
|
+
return candidate.retry ?? (IDEMPOTENT_TOOL_NAMES.has(candidate.tool.name) ||
|
|
240
240
|
candidate.owner.startsWith("subagent:")
|
|
241
241
|
? "idempotent"
|
|
242
|
-
: "non-idempotent";
|
|
242
|
+
: "non-idempotent");
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
// 把工具候选整理成版本描述里要保存的稳定字段。
|
|
@@ -543,6 +543,25 @@ export interface CreatePreparedPiTurnOptions {
|
|
|
543
543
|
readonly durability: PiTurnDurability;
|
|
544
544
|
/** Reports paired model-generation lifecycle facts to the Runtime owner. */
|
|
545
545
|
readonly onGeneration?: PiGenerationLifecycleObserver;
|
|
546
|
+
/** Reports Code Mode child Tool starts without adding Pi recovery state. */
|
|
547
|
+
readonly onNestedToolStarted?: (input: Readonly<{
|
|
548
|
+
parentToolCallId: string;
|
|
549
|
+
toolCallId: string;
|
|
550
|
+
toolName: string;
|
|
551
|
+
input: unknown;
|
|
552
|
+
occurredAt: number;
|
|
553
|
+
}>) => void;
|
|
554
|
+
/** Reports Code Mode child Tool outcomes without adding Pi settlements. */
|
|
555
|
+
readonly onNestedToolFinished?: (input: Readonly<{
|
|
556
|
+
parentToolCallId: string;
|
|
557
|
+
toolCallId: string;
|
|
558
|
+
toolName: string;
|
|
559
|
+
outcome: "completed" | "failed" | "cancelled";
|
|
560
|
+
durationMs: number;
|
|
561
|
+
output?: import("@earendil-works/pi-agent-core").AgentToolResult<unknown>;
|
|
562
|
+
error?: unknown;
|
|
563
|
+
occurredAt: number;
|
|
564
|
+
}>) => void;
|
|
546
565
|
/** Per-Submission executors for tools whose metadata is fixed at assembly time. */
|
|
547
566
|
readonly toolExecutors?: Readonly<Record<
|
|
548
567
|
string,
|
|
@@ -634,6 +653,7 @@ export class PreparedPiTurnAdapter {
|
|
|
634
653
|
private readonly turn: PiTurnAdapter;
|
|
635
654
|
private readonly abortController = new AbortController();
|
|
636
655
|
private readonly candidates: readonly PiToolCandidate[];
|
|
656
|
+
private nestedToolOrdinal = 0;
|
|
637
657
|
private assistantOrdinal: number;
|
|
638
658
|
private readonly encoder: PiChunkEncoder;
|
|
639
659
|
private readonly steerMessageIds: string[] = [];
|
|
@@ -805,12 +825,44 @@ export class PreparedPiTurnAdapter {
|
|
|
805
825
|
}
|
|
806
826
|
const execute = options.toolExecutors?.[candidate.tool.name] ??
|
|
807
827
|
candidate.tool.execute;
|
|
808
|
-
|
|
809
|
-
toolCallId,
|
|
828
|
+
if (recordRecoveryAttempt || !toolCallIdPrefix) {
|
|
829
|
+
return execute(toolCallId, input, signal, onUpdate);
|
|
830
|
+
}
|
|
831
|
+
const startedAt = Date.now();
|
|
832
|
+
const telemetryToolCallId = `${toolCallId}:${++this.nestedToolOrdinal}`;
|
|
833
|
+
options.onNestedToolStarted?.({
|
|
834
|
+
parentToolCallId: toolCallIdPrefix,
|
|
835
|
+
toolCallId: telemetryToolCallId,
|
|
836
|
+
toolName: candidate.tool.name,
|
|
810
837
|
input,
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
838
|
+
occurredAt: startedAt,
|
|
839
|
+
});
|
|
840
|
+
try {
|
|
841
|
+
const output = await execute(toolCallId, input, signal, onUpdate);
|
|
842
|
+
const occurredAt = Date.now();
|
|
843
|
+
options.onNestedToolFinished?.({
|
|
844
|
+
parentToolCallId: toolCallIdPrefix,
|
|
845
|
+
toolCallId: telemetryToolCallId,
|
|
846
|
+
toolName: candidate.tool.name,
|
|
847
|
+
outcome: "completed",
|
|
848
|
+
durationMs: occurredAt - startedAt,
|
|
849
|
+
output,
|
|
850
|
+
occurredAt,
|
|
851
|
+
});
|
|
852
|
+
return output;
|
|
853
|
+
} catch (error) {
|
|
854
|
+
const occurredAt = Date.now();
|
|
855
|
+
options.onNestedToolFinished?.({
|
|
856
|
+
parentToolCallId: toolCallIdPrefix,
|
|
857
|
+
toolCallId: telemetryToolCallId,
|
|
858
|
+
toolName: candidate.tool.name,
|
|
859
|
+
outcome: signal?.aborted ? "cancelled" : "failed",
|
|
860
|
+
durationMs: occurredAt - startedAt,
|
|
861
|
+
error,
|
|
862
|
+
occurredAt,
|
|
863
|
+
});
|
|
864
|
+
throw error;
|
|
865
|
+
}
|
|
814
866
|
},
|
|
815
867
|
},
|
|
816
868
|
});
|
package/src/pi/tool/compiler.ts
CHANGED
|
@@ -66,6 +66,8 @@ export interface PiToolCandidate {
|
|
|
66
66
|
* 那是失效不是降级。`deny` 仍然优先,被 deny 的工具根本不会注入。
|
|
67
67
|
*/
|
|
68
68
|
readonly alwaysRequiresApproval?: boolean;
|
|
69
|
+
/** Recovery may replay this Tool Call only when the candidate guarantees convergence. */
|
|
70
|
+
readonly retry?: "idempotent" | "non-idempotent";
|
|
69
71
|
readonly summary?: string;
|
|
70
72
|
readonly source?: ApprovalReceipt["source"];
|
|
71
73
|
readonly interaction?: PiToolInteractionSpec;
|
package/src/pi/tool/declared.ts
CHANGED
|
@@ -50,6 +50,7 @@ export interface PiDeclaredToolPolicy<Reply = unknown> {
|
|
|
50
50
|
readonly requiredExecutionLevel: PiToolCandidate["requiredExecutionLevel"];
|
|
51
51
|
readonly requiredExecutionLevelForInput?: PiToolCandidate["requiredExecutionLevelForInput"];
|
|
52
52
|
readonly direct?: true;
|
|
53
|
+
readonly retry?: PiToolCandidate["retry"];
|
|
53
54
|
readonly source?: PiToolCandidate["source"];
|
|
54
55
|
readonly summary?: string;
|
|
55
56
|
/**
|
|
@@ -116,6 +117,7 @@ export function createPiDeclaredToolCandidate<Reply = unknown>(
|
|
|
116
117
|
? { requiredExecutionLevelForInput: policy.requiredExecutionLevelForInput }
|
|
117
118
|
: {}),
|
|
118
119
|
...(policy.direct ? { direct: policy.direct } : {}),
|
|
120
|
+
...(policy.retry ? { retry: policy.retry } : {}),
|
|
119
121
|
...(policy.source ? { source: policy.source } : {}),
|
|
120
122
|
};
|
|
121
123
|
}
|
package/src/runtime.ts
CHANGED
|
@@ -975,6 +975,28 @@ export abstract class AgentRuntimeKernel<
|
|
|
975
975
|
occurredAt: event.timestamp,
|
|
976
976
|
});
|
|
977
977
|
},
|
|
978
|
+
onNestedToolStarted: (event) => {
|
|
979
|
+
this.telemetry.capture("toolStarted", {
|
|
980
|
+
submissionId: submission.submissionId,
|
|
981
|
+
...event,
|
|
982
|
+
});
|
|
983
|
+
},
|
|
984
|
+
onNestedToolFinished: (event) => {
|
|
985
|
+
this.telemetry.capture("toolFinished", {
|
|
986
|
+
submissionId: submission.submissionId,
|
|
987
|
+
parentToolCallId: event.parentToolCallId,
|
|
988
|
+
toolCallId: event.toolCallId,
|
|
989
|
+
toolName: event.toolName,
|
|
990
|
+
outcome: event.outcome,
|
|
991
|
+
durationMs: event.durationMs,
|
|
992
|
+
...(event.output ? {
|
|
993
|
+
output: event.output,
|
|
994
|
+
outputBytes: json(event.output).length,
|
|
995
|
+
} : {}),
|
|
996
|
+
...(event.error ? { error: errorText(event.error) } : {}),
|
|
997
|
+
occurredAt: event.occurredAt,
|
|
998
|
+
});
|
|
999
|
+
},
|
|
978
1000
|
...(toolExecutors && Object.keys(toolExecutors).length > 0
|
|
979
1001
|
? { toolExecutors }
|
|
980
1002
|
: {}),
|
|
@@ -223,6 +223,7 @@ export class RuntimeTelemetry {
|
|
|
223
223
|
submissionId: string;
|
|
224
224
|
toolCallId: string;
|
|
225
225
|
toolName: string;
|
|
226
|
+
parentToolCallId?: string;
|
|
226
227
|
input?: unknown;
|
|
227
228
|
occurredAt?: number;
|
|
228
229
|
}>): TelemetryRecordResult {
|
|
@@ -235,10 +236,9 @@ export class RuntimeTelemetry {
|
|
|
235
236
|
...(input.input === undefined ? {} : { input: input.input as never }),
|
|
236
237
|
}, {
|
|
237
238
|
...input,
|
|
238
|
-
parentOperationId:
|
|
239
|
-
|
|
240
|
-
input.submissionId,
|
|
241
|
-
),
|
|
239
|
+
parentOperationId: input.parentToolCallId
|
|
240
|
+
? telemetryOperations.tool(input.submissionId, input.parentToolCallId)
|
|
241
|
+
: telemetryOperations.turn(this.resource.sessionId, input.submissionId),
|
|
242
242
|
});
|
|
243
243
|
}
|
|
244
244
|
|
|
@@ -246,6 +246,7 @@ export class RuntimeTelemetry {
|
|
|
246
246
|
submissionId: string;
|
|
247
247
|
toolCallId: string;
|
|
248
248
|
toolName: string;
|
|
249
|
+
parentToolCallId?: string;
|
|
249
250
|
outcome: "completed" | "failed" | "cancelled";
|
|
250
251
|
durationMs?: number;
|
|
251
252
|
outputBytes?: number;
|
|
@@ -268,10 +269,9 @@ export class RuntimeTelemetry {
|
|
|
268
269
|
...(input.error ? { error: input.error } : {}),
|
|
269
270
|
}, {
|
|
270
271
|
...input,
|
|
271
|
-
parentOperationId:
|
|
272
|
-
|
|
273
|
-
input.submissionId,
|
|
274
|
-
),
|
|
272
|
+
parentOperationId: input.parentToolCallId
|
|
273
|
+
? telemetryOperations.tool(input.submissionId, input.parentToolCallId)
|
|
274
|
+
: telemetryOperations.turn(this.resource.sessionId, input.submissionId),
|
|
275
275
|
});
|
|
276
276
|
}
|
|
277
277
|
|