@peer-agent/runtime-sdk 0.1.0-rc.3 → 0.1.0-rc.31
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/contracts.d.ts +8 -2
- package/dist/index.d.ts +1 -1
- package/dist/pipeline-contracts.d.ts +14 -2
- package/dist/pipeline.js +66 -26
- package/dist/runtime.js +7 -1
- package/package.json +3 -3
package/dist/contracts.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ContextAccountingSnapshot, RuntimeExecuteRequest, RuntimeExecution
|
|
|
3
3
|
export type { RuntimeExecuteRequest, RuntimeExecutionContext, RuntimeToolCall, RuntimeToolResult, } from '@peer-agent/protocol';
|
|
4
4
|
export declare const RUNTIME_EVENT_PROTOCOL_VERSION: 1;
|
|
5
5
|
export type RuntimeEventProtocolVersion = typeof RUNTIME_EVENT_PROTOCOL_VERSION;
|
|
6
|
-
export type RuntimeSdkEventType = 'session.started' | 'message.delta' | 'reasoning.delta' | 'message.completed' | 'runtime.error' | 'tool.started' | 'hook.completed' | 'permission.requested' | 'permission.resolved' | 'tool.completed' | 'compaction.progress' | 'context.accounting';
|
|
6
|
+
export type RuntimeSdkEventType = 'session.started' | 'message.delta' | 'reasoning.delta' | 'stream.discard' | 'message.completed' | 'runtime.error' | 'tool.started' | 'hook.completed' | 'permission.requested' | 'permission.resolved' | 'tool.completed' | 'compaction.progress' | 'context.accounting';
|
|
7
7
|
export type RuntimeSdkToolCall = RuntimeToolCall;
|
|
8
8
|
export type RuntimeSdkExecuteRequest = RuntimeExecuteRequest;
|
|
9
9
|
export type RuntimeSdkExecutionContext = RuntimeExecutionContext;
|
|
@@ -93,6 +93,12 @@ export interface RuntimeSdkReasoningDeltaEvent extends RuntimeSdkEventBase {
|
|
|
93
93
|
* Mid-turn / automatic compaction progress for host UI surfaces.
|
|
94
94
|
* percent is 0-100; hosts should treat values below 100 as live progress.
|
|
95
95
|
*/
|
|
96
|
+
export interface RuntimeSdkStreamDiscardEvent extends RuntimeSdkEventBase {
|
|
97
|
+
readonly type: 'stream.discard';
|
|
98
|
+
readonly streamId: string;
|
|
99
|
+
readonly textChars: number;
|
|
100
|
+
readonly reasoningChars: number;
|
|
101
|
+
}
|
|
96
102
|
export interface RuntimeSdkCompactionProgressEvent extends RuntimeSdkEventBase {
|
|
97
103
|
readonly type: 'compaction.progress';
|
|
98
104
|
readonly streamId: string;
|
|
@@ -153,7 +159,7 @@ export interface RuntimeSdkToolCompletedEvent extends RuntimeSdkEventBase {
|
|
|
153
159
|
readonly decision: RuntimeDecision;
|
|
154
160
|
readonly result: RuntimeSdkToolResult;
|
|
155
161
|
}
|
|
156
|
-
export type RuntimeSdkEvent = RuntimeSdkSessionStartedEvent | RuntimeSdkMessageDeltaEvent | RuntimeSdkReasoningDeltaEvent | RuntimeSdkCompactionProgressEvent | RuntimeSdkContextAccountingEvent | RuntimeSdkMessageCompletedEvent | RuntimeSdkRuntimeErrorEvent | RuntimeSdkToolStartedEvent | RuntimeSdkHookCompletedEvent | RuntimeSdkPermissionRequestedEvent | RuntimeSdkPermissionResolvedEvent | RuntimeSdkToolCompletedEvent;
|
|
162
|
+
export type RuntimeSdkEvent = RuntimeSdkSessionStartedEvent | RuntimeSdkMessageDeltaEvent | RuntimeSdkReasoningDeltaEvent | RuntimeSdkStreamDiscardEvent | RuntimeSdkCompactionProgressEvent | RuntimeSdkContextAccountingEvent | RuntimeSdkMessageCompletedEvent | RuntimeSdkRuntimeErrorEvent | RuntimeSdkToolStartedEvent | RuntimeSdkHookCompletedEvent | RuntimeSdkPermissionRequestedEvent | RuntimeSdkPermissionResolvedEvent | RuntimeSdkToolCompletedEvent;
|
|
157
163
|
export type RuntimeSdkEventInput = RuntimeSdkEvent extends infer Event ? Event extends RuntimeSdkEvent ? Omit<Event, 'protocolVersion' | 'eventId' | 'sequence' | 'occurredAt'> : never : never;
|
|
158
164
|
export type RuntimeSdkEventListener = (event: RuntimeSdkEvent) => void;
|
|
159
165
|
export interface RuntimeSdkOptions {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { RUNTIME_EVENT_PROTOCOL_VERSION } from './contracts.ts';
|
|
2
|
-
export type { RuntimeEventProtocolVersion, RuntimeExecuteRequest, RuntimeExecutionContext, RuntimeToolCall, RuntimeToolResult, RuntimeSdk, RuntimeSdkApprovalDecision, RuntimeSdkApprovalPort, RuntimeSdkEvent, RuntimeSdkEventBase, RuntimeSdkEventInput, RuntimeSdkEventListener, RuntimeSdkEventType, RuntimeSdkSessionStartedEvent, RuntimeSdkMessageDeltaEvent, RuntimeSdkReasoningDeltaEvent, RuntimeSdkCompactionProgressEvent, RuntimeSdkContextAccountingEvent, RuntimeSdkMessageCompletedEvent, RuntimeSdkRuntimeErrorEvent, RuntimeSdkHookCompletedEvent, RuntimeSdkPermissionRequestedEvent, RuntimeSdkPermissionResolvedEvent, RuntimeSdkToolCompletedEvent, RuntimeSdkToolStartedEvent, RuntimeSdkExecuteRequest, RuntimeSdkExecutionContext, RuntimeSdkHookPayload, RuntimeSdkHookRecord, RuntimeSdkHookRunner, RuntimeSdkHostAdapter, RuntimeSdkOptions, RuntimeSdkPermissionRequest, RuntimeSdkProviderExecution, RuntimeSdkToolCall, RuntimeSdkToolResult, } from './contracts.ts';
|
|
2
|
+
export type { RuntimeEventProtocolVersion, RuntimeExecuteRequest, RuntimeExecutionContext, RuntimeToolCall, RuntimeToolResult, RuntimeSdk, RuntimeSdkApprovalDecision, RuntimeSdkApprovalPort, RuntimeSdkEvent, RuntimeSdkEventBase, RuntimeSdkEventInput, RuntimeSdkEventListener, RuntimeSdkEventType, RuntimeSdkSessionStartedEvent, RuntimeSdkMessageDeltaEvent, RuntimeSdkReasoningDeltaEvent, RuntimeSdkStreamDiscardEvent, RuntimeSdkCompactionProgressEvent, RuntimeSdkContextAccountingEvent, RuntimeSdkMessageCompletedEvent, RuntimeSdkRuntimeErrorEvent, RuntimeSdkHookCompletedEvent, RuntimeSdkPermissionRequestedEvent, RuntimeSdkPermissionResolvedEvent, RuntimeSdkToolCompletedEvent, RuntimeSdkToolStartedEvent, RuntimeSdkExecuteRequest, RuntimeSdkExecutionContext, RuntimeSdkHookPayload, RuntimeSdkHookRecord, RuntimeSdkHookRunner, RuntimeSdkHostAdapter, RuntimeSdkOptions, RuntimeSdkPermissionRequest, RuntimeSdkProviderExecution, RuntimeSdkToolCall, RuntimeSdkToolResult, } from './contracts.ts';
|
|
3
3
|
export type { RuntimePipeline, RuntimePipelineCompletedTurn, RuntimePipelineContinueTurn, RuntimePipelineEventSink, RuntimePipelineLifecycleObserver, RuntimePipelineModelAdapter, RuntimePipelineOptions, RuntimePipelineRunInput, RuntimePipelineRunResult, RuntimePipelineStatus, RuntimePipelineToolCall, RuntimePipelineToolCallsTurn, RuntimePipelineToolExecution, RuntimePipelineToolExecutor, RuntimePipelineTurnContext, RuntimePipelineTurnResult, } from './pipeline-contracts.ts';
|
|
4
4
|
export { createRuntimePipeline } from './pipeline.ts';
|
|
5
5
|
export { createRuntimeSdk } from './runtime.ts';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RuntimeSdkEvent, RuntimeSdkEventInput, RuntimeSdkToolResult } from './contracts.ts';
|
|
2
|
-
export type RuntimePipelineStatus = 'completed' | 'stopped' | 'cancelled' | 'exhausted' | 'failed';
|
|
2
|
+
export type RuntimePipelineStatus = 'completed' | 'stopped' | 'cancelled' | 'yielded' | 'exhausted' | 'failed';
|
|
3
3
|
export interface RuntimePipelineRunInput<TInput = unknown> {
|
|
4
4
|
readonly sessionId: string;
|
|
5
5
|
readonly streamId?: string;
|
|
@@ -9,6 +9,13 @@ export interface RuntimePipelineRunInput<TInput = unknown> {
|
|
|
9
9
|
readonly model?: string;
|
|
10
10
|
readonly input: TInput;
|
|
11
11
|
readonly maxTurns?: number;
|
|
12
|
+
readonly maxToolCalls?: number;
|
|
13
|
+
/** Scheduling allowance; unlike maxToolCalls this can end at a batch boundary. */
|
|
14
|
+
readonly sliceToolCalls?: number;
|
|
15
|
+
readonly yieldAtTurnLimit?: boolean;
|
|
16
|
+
/** Host scheduling request, checked at durable batch boundaries. */
|
|
17
|
+
readonly shouldYield?: () => boolean;
|
|
18
|
+
readonly maxToolBatchCalls?: number;
|
|
12
19
|
}
|
|
13
20
|
export interface RuntimePipelineToolCall<TPayload = unknown> {
|
|
14
21
|
readonly toolCallId: string;
|
|
@@ -49,12 +56,17 @@ export interface RuntimePipelineModelAdapter<TInput = unknown, TState = unknown,
|
|
|
49
56
|
initialize(input: RuntimePipelineRunInput<TInput>, context: RuntimePipelineTurnContext<TInput>): TState | Promise<TState>;
|
|
50
57
|
runTurn(state: TState, context: RuntimePipelineTurnContext<TInput>): RuntimePipelineTurnResult<TState, TCall, TOutput> | Promise<RuntimePipelineTurnResult<TState, TCall, TOutput>>;
|
|
51
58
|
applyToolResults(state: TState, executions: readonly RuntimePipelineToolExecution<TCall, TToolResult>[], context: RuntimePipelineTurnContext<TInput>): TState | Promise<TState>;
|
|
59
|
+
/** Critical durable commit after paired tool results; failure ends execution. */
|
|
60
|
+
checkpoint?(state: TState, executions: readonly RuntimePipelineToolExecution<TCall, TToolResult>[], context: RuntimePipelineTurnContext<TInput>): void | Promise<void>;
|
|
52
61
|
onCompleted?(state: TState, output: TOutput | undefined, context: RuntimePipelineTurnContext<TInput>): void | Promise<void>;
|
|
53
62
|
onStopped?(state: TState, executions: readonly RuntimePipelineToolExecution<TCall, TToolResult>[], context: RuntimePipelineTurnContext<TInput>): void | Promise<void>;
|
|
54
63
|
onCancelled?(state: TState | undefined, context: RuntimePipelineTurnContext<TInput>): void | Promise<void>;
|
|
55
|
-
|
|
64
|
+
onYield?(state: TState, context: RuntimePipelineTurnContext<TInput>): void | Promise<void>;
|
|
65
|
+
onExhausted?(state: TState, context: RuntimePipelineTurnContext<TInput>, reason: 'max_turns_exceeded' | 'max_tool_calls_exceeded'): void | Promise<void>;
|
|
56
66
|
}
|
|
57
67
|
export interface RuntimePipelineToolExecutor<TInput = unknown, TCall extends RuntimePipelineToolCall = RuntimePipelineToolCall, TToolResult = RuntimeSdkToolResult> {
|
|
68
|
+
/** Build a paired, explicit non-execution result without dispatching a capability. */
|
|
69
|
+
notExecuted?(call: TCall, reason: string): RuntimePipelineToolExecution<TCall, TToolResult> | Promise<RuntimePipelineToolExecution<TCall, TToolResult>>;
|
|
58
70
|
execute(call: TCall, context: RuntimePipelineTurnContext<TInput> & {
|
|
59
71
|
readonly index: number;
|
|
60
72
|
}): RuntimePipelineToolExecution<TCall, TToolResult> | Promise<RuntimePipelineToolExecution<TCall, TToolResult>>;
|
package/dist/pipeline.js
CHANGED
|
@@ -34,6 +34,10 @@ export function createRuntimePipeline(options) {
|
|
|
34
34
|
throw new Error('RuntimePipeline run requires sessionId.');
|
|
35
35
|
const signal = context.signal;
|
|
36
36
|
const maxTurns = normalizeMaxTurns(input.maxTurns, defaultMaxTurns);
|
|
37
|
+
const maxToolCalls = Number.isFinite(input.maxToolCalls)
|
|
38
|
+
? Math.max(0, Math.floor(input.maxToolCalls)) : Number.POSITIVE_INFINITY;
|
|
39
|
+
const sliceToolCalls = Number.isFinite(input.sliceToolCalls) ? Math.max(1, input.sliceToolCalls) : Infinity;
|
|
40
|
+
const maxBatch = Number.isFinite(input.maxToolBatchCalls) ? Math.max(1, input.maxToolBatchCalls) : Infinity;
|
|
37
41
|
let state;
|
|
38
42
|
let turns = 0;
|
|
39
43
|
let toolCalls = 0;
|
|
@@ -56,6 +60,15 @@ export function createRuntimePipeline(options) {
|
|
|
56
60
|
signal,
|
|
57
61
|
emit,
|
|
58
62
|
});
|
|
63
|
+
const exhaust = async (reason) => {
|
|
64
|
+
await options.model.onExhausted?.(state, turnContext(turns), reason);
|
|
65
|
+
emit({ type: 'runtime.error', ...eventBase, code: reason, message: reason });
|
|
66
|
+
return { status: 'exhausted', state, turns, toolCalls, reason };
|
|
67
|
+
};
|
|
68
|
+
const yieldRun = async () => {
|
|
69
|
+
await options.model.onYield?.(state, turnContext(turns));
|
|
70
|
+
return { status: 'yielded', state, turns, toolCalls, reason: 'scheduling_slice' };
|
|
71
|
+
};
|
|
59
72
|
try {
|
|
60
73
|
throwIfAborted(signal);
|
|
61
74
|
emit({
|
|
@@ -68,12 +81,17 @@ export function createRuntimePipeline(options) {
|
|
|
68
81
|
state = await options.model.initialize(input, turnContext(0));
|
|
69
82
|
for (let turn = 0; turn < maxTurns; turn += 1) {
|
|
70
83
|
throwIfAborted(signal);
|
|
84
|
+
if (input.shouldYield?.() === true)
|
|
85
|
+
return await yieldRun();
|
|
71
86
|
turns = turn + 1;
|
|
72
87
|
const currentContext = turnContext(turn);
|
|
73
88
|
const outcome = await options.model.runTurn(state, currentContext);
|
|
74
89
|
state = outcome.state;
|
|
75
|
-
if (outcome.kind === 'continue')
|
|
90
|
+
if (outcome.kind === 'continue') {
|
|
91
|
+
if (input.shouldYield?.() === true)
|
|
92
|
+
return await yieldRun();
|
|
76
93
|
continue;
|
|
94
|
+
}
|
|
77
95
|
if (outcome.kind === 'completed') {
|
|
78
96
|
await options.model.onCompleted?.(state, outcome.output, currentContext);
|
|
79
97
|
if (input.streamId) {
|
|
@@ -93,30 +111,65 @@ export function createRuntimePipeline(options) {
|
|
|
93
111
|
...(outcome.reason ? { reason: outcome.reason } : {}),
|
|
94
112
|
};
|
|
95
113
|
}
|
|
114
|
+
// Reserve the whole batch before dispatch. Never execute a partial
|
|
115
|
+
// write batch or exceed a caller's remaining budget inside one turn.
|
|
116
|
+
if (outcome.calls.length > maxBatch)
|
|
117
|
+
throw new Error('tool_batch_too_large');
|
|
118
|
+
if (toolCalls + outcome.calls.length > maxToolCalls) {
|
|
119
|
+
if (options.tools.notExecuted) {
|
|
120
|
+
const denied = await Promise.all(outcome.calls.map(call => options.tools.notExecuted(call, 'max_tool_calls_exceeded')));
|
|
121
|
+
state = await options.model.applyToolResults(state, denied, currentContext);
|
|
122
|
+
await options.model.checkpoint?.(state, denied, currentContext);
|
|
123
|
+
}
|
|
124
|
+
return await exhaust('max_tool_calls_exceeded');
|
|
125
|
+
}
|
|
96
126
|
const executions = [];
|
|
97
127
|
if (isParallelSafeLocalToolBatch(outcome.calls)) {
|
|
98
128
|
const batch = await Promise.all(outcome.calls.map(async (call, index) => {
|
|
129
|
+
if (signal?.aborted && options.tools.notExecuted)
|
|
130
|
+
return options.tools.notExecuted(call, 'cancelled');
|
|
99
131
|
throwIfAborted(signal);
|
|
100
|
-
|
|
101
|
-
...currentContext,
|
|
102
|
-
|
|
103
|
-
|
|
132
|
+
try {
|
|
133
|
+
return await options.tools.execute(call, { ...currentContext, index });
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
if (!options.tools.notExecuted)
|
|
137
|
+
throw error;
|
|
138
|
+
return options.tools.notExecuted(call, isAbortError(error) ? 'cancelled_outcome_unknown' : 'execution_outcome_unknown');
|
|
139
|
+
}
|
|
104
140
|
}));
|
|
105
141
|
executions.push(...batch);
|
|
106
142
|
toolCalls += batch.length;
|
|
107
143
|
}
|
|
108
144
|
else {
|
|
109
145
|
for (const [index, call] of outcome.calls.entries()) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
146
|
+
let execution;
|
|
147
|
+
if (signal?.aborted && options.tools.notExecuted)
|
|
148
|
+
execution = await options.tools.notExecuted(call, 'cancelled');
|
|
149
|
+
else {
|
|
150
|
+
throwIfAborted(signal);
|
|
151
|
+
try {
|
|
152
|
+
execution = await options.tools.execute(call, { ...currentContext, index });
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
if (!options.tools.notExecuted)
|
|
156
|
+
throw error;
|
|
157
|
+
execution = await options.tools.notExecuted(call, isAbortError(error) ? 'cancelled_outcome_unknown' : 'execution_outcome_unknown');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
115
160
|
executions.push(execution);
|
|
116
161
|
toolCalls += 1;
|
|
162
|
+
if (execution.terminal && options.tools.notExecuted) {
|
|
163
|
+
for (const remaining of outcome.calls.slice(index + 1))
|
|
164
|
+
executions.push(await options.tools.notExecuted(remaining, 'batch_stopped'));
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
117
167
|
}
|
|
118
168
|
}
|
|
119
169
|
state = await options.model.applyToolResults(state, executions, currentContext);
|
|
170
|
+
// Completed results remain durable even when cancellation arrived during execution.
|
|
171
|
+
await options.model.checkpoint?.(state, executions, currentContext);
|
|
172
|
+
throwIfAborted(signal);
|
|
120
173
|
try {
|
|
121
174
|
await options.lifecycle?.toolResultsApplied?.(state, executions, currentContext);
|
|
122
175
|
}
|
|
@@ -143,23 +196,10 @@ export function createRuntimePipeline(options) {
|
|
|
143
196
|
reason: terminalExecution.terminalReason || 'tool_requested_stop',
|
|
144
197
|
};
|
|
145
198
|
}
|
|
199
|
+
if (toolCalls >= sliceToolCalls || input.shouldYield?.() === true)
|
|
200
|
+
return await yieldRun();
|
|
146
201
|
}
|
|
147
|
-
|
|
148
|
-
await options.model.onExhausted?.(state, exhaustedContext);
|
|
149
|
-
const exhaustedReason = 'max_turns_exceeded';
|
|
150
|
-
emit({
|
|
151
|
-
type: 'runtime.error',
|
|
152
|
-
...eventBase,
|
|
153
|
-
code: exhaustedReason,
|
|
154
|
-
message: exhaustedReason,
|
|
155
|
-
});
|
|
156
|
-
return {
|
|
157
|
-
status: 'exhausted',
|
|
158
|
-
state,
|
|
159
|
-
turns,
|
|
160
|
-
toolCalls,
|
|
161
|
-
reason: exhaustedReason,
|
|
162
|
-
};
|
|
202
|
+
return input.yieldAtTurnLimit ? await yieldRun() : await exhaust('max_turns_exceeded');
|
|
163
203
|
}
|
|
164
204
|
catch (error) {
|
|
165
205
|
if (signal?.aborted || isAbortError(error)) {
|
package/dist/runtime.js
CHANGED
|
@@ -130,9 +130,15 @@ export function createRuntimeSdk(options) {
|
|
|
130
130
|
decision: mostRestrictiveHookDecision(postRecords),
|
|
131
131
|
records: postRecords,
|
|
132
132
|
});
|
|
133
|
-
|
|
133
|
+
let result = options.host.appendHookEvidence
|
|
134
134
|
? options.host.appendHookEvidence(execution.result, [...preRecords, ...postRecords], preDecision)
|
|
135
135
|
: execution.result;
|
|
136
|
+
// Host-only sideband must survive a Hook Evidence clone without becoming
|
|
137
|
+
// enumerable event/storage data. Model-supplied fields cannot create it.
|
|
138
|
+
const sideband = Object.getOwnPropertyDescriptor(execution.result, 'modelContext');
|
|
139
|
+
if (result !== execution.result && sideband && sideband.enumerable === false) {
|
|
140
|
+
result = Object.defineProperty({ ...result }, 'modelContext', sideband);
|
|
141
|
+
}
|
|
136
142
|
const resolvedExecution = { ...execution, result };
|
|
137
143
|
emit({ type: 'tool.completed', ...eventBase, decision: preDecision, result });
|
|
138
144
|
return resolvedExecution;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peer-agent/runtime-sdk",
|
|
3
|
-
"version": "0.1.0-rc.
|
|
3
|
+
"version": "0.1.0-rc.31",
|
|
4
4
|
"description": "Public host-neutral orchestration SDK for Peer Agent runtimes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"LICENSE"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@peer-agent/protocol": "^0.1.0-rc.
|
|
38
|
-
"@peer-agent/runtime-core": "^0.1.0-rc.
|
|
37
|
+
"@peer-agent/protocol": "^0.1.0-rc.31",
|
|
38
|
+
"@peer-agent/runtime-core": "^0.1.0-rc.31"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"typescript": "^5.9.3"
|