@astralyn/pi 1.4.5 → 1.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/dist/bundle/chunks/chunk-FODCTZXW.js +230 -0
- package/dist/bundle/chunks/{chunk-I5S7H7GA.js → chunk-FYKNSJG6.js} +1 -1
- package/dist/bundle/chunks/{chunk-AXFWZIHH.js → chunk-MG5XDTXV.js} +1 -1
- package/dist/bundle/chunks/{chunk-ALHAFUHP.js → chunk-PU2IWWXV.js} +1 -1
- package/dist/bundle/chunks/{chunk-5M3YJ54Z.js → chunk-RO2VH6UZ.js} +1 -1
- package/dist/bundle/chunks/chunk-YJTSOLP2.js +1499 -0
- package/dist/bundle/chunks/{cli-FH77R7JR.js → cli-MEL7SGJD.js} +1 -1
- package/dist/bundle/chunks/{execute-GMFGC27P.js → execute-4CWRNHPO.js} +1 -1
- package/dist/bundle/chunks/{runtime-R5CMHJ5P.js → runtime-R3X67XMR.js} +1 -1
- package/dist/bundle/chunks/{virtual-modules-6FUV7ZDV.js → virtual-modules-PKEOKGYI.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/agent-session.d.ts +0 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +0 -4
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/isolated-session.d.ts +23 -0
- package/dist/core/isolated-session.d.ts.map +1 -0
- package/dist/core/isolated-session.js +55 -0
- package/dist/core/isolated-session.js.map +1 -0
- package/dist/core/package-manager.d.ts +7 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +72 -1
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +23 -7
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +4 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +11 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-schema.d.ts +7 -0
- package/dist/core/settings-schema.d.ts.map +1 -1
- package/dist/core/settings-schema.js +6 -0
- package/dist/core/settings-schema.js.map +1 -1
- package/dist/core/skills.d.ts +10 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +23 -0
- package/dist/core/skills.js.map +1 -1
- package/dist/core/tasks/codec.d.ts +12 -0
- package/dist/core/tasks/codec.d.ts.map +1 -0
- package/dist/core/tasks/codec.js +139 -0
- package/dist/core/tasks/codec.js.map +1 -0
- package/dist/core/tasks/delivery.d.ts +11 -4
- package/dist/core/tasks/delivery.d.ts.map +1 -1
- package/dist/core/tasks/delivery.js +9 -9
- package/dist/core/tasks/delivery.js.map +1 -1
- package/dist/core/tasks/execution.d.ts +71 -0
- package/dist/core/tasks/execution.d.ts.map +1 -0
- package/dist/core/tasks/execution.js +292 -0
- package/dist/core/tasks/execution.js.map +1 -0
- package/dist/core/tasks/format.d.ts +0 -2
- package/dist/core/tasks/format.d.ts.map +1 -1
- package/dist/core/tasks/format.js +1 -16
- package/dist/core/tasks/format.js.map +1 -1
- package/dist/core/tasks/limits.d.ts +12 -1
- package/dist/core/tasks/limits.d.ts.map +1 -1
- package/dist/core/tasks/limits.js +20 -1
- package/dist/core/tasks/limits.js.map +1 -1
- package/dist/core/tasks/output.d.ts +17 -17
- package/dist/core/tasks/output.d.ts.map +1 -1
- package/dist/core/tasks/output.js +72 -69
- package/dist/core/tasks/output.js.map +1 -1
- package/dist/core/tasks/presentation.d.ts +14 -5
- package/dist/core/tasks/presentation.d.ts.map +1 -1
- package/dist/core/tasks/presentation.js +56 -185
- package/dist/core/tasks/presentation.js.map +1 -1
- package/dist/core/tasks/record.d.ts +45 -0
- package/dist/core/tasks/record.d.ts.map +1 -0
- package/dist/core/tasks/record.js +80 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/runtime.d.ts +22 -22
- package/dist/core/tasks/runtime.d.ts.map +1 -1
- package/dist/core/tasks/runtime.js +170 -343
- package/dist/core/tasks/runtime.js.map +1 -1
- package/dist/core/tasks/scheduler.d.ts +16 -0
- package/dist/core/tasks/scheduler.d.ts.map +1 -0
- package/dist/core/tasks/scheduler.js +42 -0
- package/dist/core/tasks/scheduler.js.map +1 -0
- package/dist/core/tasks/session.d.ts +1 -1
- package/dist/core/tasks/session.d.ts.map +1 -1
- package/dist/core/tasks/session.js +22 -35
- package/dist/core/tasks/session.js.map +1 -1
- package/dist/core/tasks/store.d.ts +18 -25
- package/dist/core/tasks/store.d.ts.map +1 -1
- package/dist/core/tasks/store.js +45 -43
- package/dist/core/tasks/store.js.map +1 -1
- package/dist/core/tasks/types.d.ts +159 -70
- package/dist/core/tasks/types.d.ts.map +1 -1
- package/dist/core/tasks/types.js +3 -9
- package/dist/core/tasks/types.js.map +1 -1
- package/dist/core/tools/shell-execution.d.ts +8 -7
- package/dist/core/tools/shell-execution.d.ts.map +1 -1
- package/dist/core/tools/shell-execution.js +19 -27
- package/dist/core/tools/shell-execution.js.map +1 -1
- package/dist/core/tools/shell-tool.d.ts.map +1 -1
- package/dist/core/tools/shell-tool.js +42 -47
- package/dist/core/tools/shell-tool.js.map +1 -1
- package/dist/core/usage-totals.d.ts +4 -3
- package/dist/core/usage-totals.d.ts.map +1 -1
- package/dist/core/usage-totals.js +32 -8
- package/dist/core/usage-totals.js.map +1 -1
- package/dist/extensions/agent/activity.d.ts +4 -4
- package/dist/extensions/agent/activity.d.ts.map +1 -1
- package/dist/extensions/agent/activity.js +15 -24
- package/dist/extensions/agent/activity.js.map +1 -1
- package/dist/extensions/agent/index.d.ts +2 -11
- package/dist/extensions/agent/index.d.ts.map +1 -1
- package/dist/extensions/agent/index.js +3 -88
- package/dist/extensions/agent/index.js.map +1 -1
- package/dist/extensions/agent/progress.d.ts +31 -0
- package/dist/extensions/agent/progress.d.ts.map +1 -0
- package/dist/extensions/agent/progress.js +135 -0
- package/dist/extensions/agent/progress.js.map +1 -0
- package/dist/extensions/agent/render.d.ts.map +1 -1
- package/dist/extensions/agent/render.js +8 -17
- package/dist/extensions/agent/render.js.map +1 -1
- package/dist/extensions/agent/report.d.ts +9 -0
- package/dist/extensions/agent/report.d.ts.map +1 -0
- package/dist/extensions/agent/report.js +40 -0
- package/dist/extensions/agent/report.js.map +1 -0
- package/dist/extensions/agent/settings-panel.d.ts +43 -0
- package/dist/extensions/agent/settings-panel.d.ts.map +1 -0
- package/dist/extensions/agent/settings-panel.js +125 -0
- package/dist/extensions/agent/settings-panel.js.map +1 -0
- package/dist/extensions/agent/settings.d.ts +1 -1
- package/dist/extensions/agent/settings.d.ts.map +1 -1
- package/dist/extensions/agent/settings.js +101 -83
- package/dist/extensions/agent/settings.js.map +1 -1
- package/dist/extensions/agent/tool.d.ts +13 -0
- package/dist/extensions/agent/tool.d.ts.map +1 -0
- package/dist/extensions/agent/tool.js +88 -0
- package/dist/extensions/agent/tool.js.map +1 -0
- package/dist/extensions/agent/types.d.ts +19 -21
- package/dist/extensions/agent/types.d.ts.map +1 -1
- package/dist/extensions/agent/types.js +2 -10
- package/dist/extensions/agent/types.js.map +1 -1
- package/dist/extensions/agent/worker.d.ts +16 -0
- package/dist/extensions/agent/worker.d.ts.map +1 -0
- package/dist/extensions/agent/worker.js +66 -0
- package/dist/extensions/agent/worker.js.map +1 -0
- package/dist/extensions/btw/agent.d.ts +1 -1
- package/dist/extensions/btw/agent.d.ts.map +1 -1
- package/dist/extensions/btw/agent.js +3 -20
- package/dist/extensions/btw/agent.js.map +1 -1
- package/dist/extensions/cached-compaction/index.d.ts.map +1 -1
- package/dist/extensions/cached-compaction/index.js +3 -22
- package/dist/extensions/cached-compaction/index.js.map +1 -1
- package/dist/extensions/cached-compaction/render.d.ts +1 -0
- package/dist/extensions/cached-compaction/render.d.ts.map +1 -1
- package/dist/extensions/cached-compaction/render.js +42 -14
- package/dist/extensions/cached-compaction/render.js.map +1 -1
- package/dist/extensions/deepwiki/client.d.ts.map +1 -1
- package/dist/extensions/deepwiki/client.js +6 -78
- package/dist/extensions/deepwiki/client.js.map +1 -1
- package/dist/extensions/deepwiki/transport.d.ts +3 -0
- package/dist/extensions/deepwiki/transport.d.ts.map +1 -0
- package/dist/extensions/deepwiki/transport.js +96 -0
- package/dist/extensions/deepwiki/transport.js.map +1 -0
- package/dist/extensions/provider/ui/builtin-data.d.ts +3 -3
- package/dist/extensions/provider/ui/builtin-data.d.ts.map +1 -1
- package/dist/extensions/provider/ui/builtin-data.js.map +1 -1
- package/dist/extensions/provider/ui/compat.d.ts +3 -3
- package/dist/extensions/provider/ui/compat.d.ts.map +1 -1
- package/dist/extensions/provider/ui/compat.js.map +1 -1
- package/dist/extensions/provider/ui/controls.d.ts +2 -2
- package/dist/extensions/provider/ui/controls.d.ts.map +1 -1
- package/dist/extensions/provider/ui/controls.js.map +1 -1
- package/dist/extensions/provider/ui/dialogs.d.ts +3 -3
- package/dist/extensions/provider/ui/dialogs.d.ts.map +1 -1
- package/dist/extensions/provider/ui/dialogs.js.map +1 -1
- package/dist/extensions/provider/ui/dictionary.d.ts +2 -2
- package/dist/extensions/provider/ui/dictionary.d.ts.map +1 -1
- package/dist/extensions/provider/ui/dictionary.js.map +1 -1
- package/dist/extensions/provider/ui/editor.d.ts.map +1 -1
- package/dist/extensions/provider/ui/editor.js +1 -3
- package/dist/extensions/provider/ui/editor.js.map +1 -1
- package/dist/extensions/provider/ui/fetch-models.d.ts +2 -2
- package/dist/extensions/provider/ui/fetch-models.d.ts.map +1 -1
- package/dist/extensions/provider/ui/fetch-models.js.map +1 -1
- package/dist/extensions/provider/ui/model-fields.d.ts +2 -2
- package/dist/extensions/provider/ui/model-fields.d.ts.map +1 -1
- package/dist/extensions/provider/ui/model-fields.js.map +1 -1
- package/dist/extensions/provider/ui/model-options.d.ts +6 -6
- package/dist/extensions/provider/ui/model-options.d.ts.map +1 -1
- package/dist/extensions/provider/ui/model-options.js.map +1 -1
- package/dist/extensions/provider/ui/pane.d.ts +21 -12
- package/dist/extensions/provider/ui/pane.d.ts.map +1 -1
- package/dist/extensions/provider/ui/pane.js.map +1 -1
- package/dist/extensions/provider/ui/provider-fields.d.ts +3 -3
- package/dist/extensions/provider/ui/provider-fields.d.ts.map +1 -1
- package/dist/extensions/provider/ui/provider-fields.js.map +1 -1
- package/dist/extensions/provider/ui/thinking-map.d.ts +2 -2
- package/dist/extensions/provider/ui/thinking-map.d.ts.map +1 -1
- package/dist/extensions/provider/ui/thinking-map.js.map +1 -1
- package/dist/extensions/run-summary/format.js +1 -1
- package/dist/extensions/run-summary/format.js.map +1 -1
- package/dist/extensions/statusline/usage.d.ts.map +1 -1
- package/dist/extensions/statusline/usage.js +2 -6
- package/dist/extensions/statusline/usage.js.map +1 -1
- package/dist/extensions/tasks/tool/actions.d.ts +1 -1
- package/dist/extensions/tasks/tool/actions.d.ts.map +1 -1
- package/dist/extensions/tasks/tool/actions.js +50 -115
- package/dist/extensions/tasks/tool/actions.js.map +1 -1
- package/dist/extensions/tasks/tool/constants.d.ts +1 -6
- package/dist/extensions/tasks/tool/constants.d.ts.map +1 -1
- package/dist/extensions/tasks/tool/constants.js +1 -6
- package/dist/extensions/tasks/tool/constants.js.map +1 -1
- package/dist/extensions/tasks/tool/schema.d.ts +0 -3
- package/dist/extensions/tasks/tool/schema.d.ts.map +1 -1
- package/dist/extensions/tasks/tool/schema.js +5 -14
- package/dist/extensions/tasks/tool/schema.js.map +1 -1
- package/dist/extensions/tasks/tool/types.d.ts +2 -8
- package/dist/extensions/tasks/tool/types.d.ts.map +1 -1
- package/dist/extensions/tasks/tool/types.js +0 -2
- package/dist/extensions/tasks/tool/types.js.map +1 -1
- package/dist/extensions/tasks/tool.d.ts.map +1 -1
- package/dist/extensions/tasks/tool.js +2 -2
- package/dist/extensions/tasks/tool.js.map +1 -1
- package/dist/extensions/tasks/ui/completion-render.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/completion-render.js +46 -47
- package/dist/extensions/tasks/ui/completion-render.js.map +1 -1
- package/dist/extensions/tasks/ui/inspector.d.ts +5 -3
- package/dist/extensions/tasks/ui/inspector.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/inspector.js +18 -6
- package/dist/extensions/tasks/ui/inspector.js.map +1 -1
- package/dist/extensions/tasks/ui/layout.d.ts +7 -7
- package/dist/extensions/tasks/ui/layout.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/layout.js +118 -84
- package/dist/extensions/tasks/ui/layout.js.map +1 -1
- package/dist/extensions/tasks/ui/list.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/list.js +45 -31
- package/dist/extensions/tasks/ui/list.js.map +1 -1
- package/dist/extensions/tasks/ui/manager.d.ts +16 -7
- package/dist/extensions/tasks/ui/manager.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/manager.js +167 -129
- package/dist/extensions/tasks/ui/manager.js.map +1 -1
- package/dist/extensions/tasks/ui/model.d.ts +29 -0
- package/dist/extensions/tasks/ui/model.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/model.js +16 -1
- package/dist/extensions/tasks/ui/model.js.map +1 -1
- package/dist/extensions/tasks/ui/render.d.ts +1 -1
- package/dist/extensions/tasks/ui/render.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/render.js +12 -9
- package/dist/extensions/tasks/ui/render.js.map +1 -1
- package/dist/extensions/tasks/ui/status.d.ts +15 -0
- package/dist/extensions/tasks/ui/status.d.ts.map +1 -0
- package/dist/extensions/tasks/ui/status.js +16 -0
- package/dist/extensions/tasks/ui/status.js.map +1 -0
- package/dist/extensions/tasks/ui/tree.js +1 -1
- package/dist/extensions/tasks/ui/tree.js.map +1 -1
- package/dist/extensions/tasks/ui/views.d.ts +10 -5
- package/dist/extensions/tasks/ui/views.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/views.js +61 -36
- package/dist/extensions/tasks/ui/views.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts +14 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +258 -7
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +2 -1
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +7 -4
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/status-marker.d.ts +2 -1
- package/dist/modes/interactive/components/status-marker.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-marker.js +0 -1
- package/dist/modes/interactive/components/status-marker.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +10 -3
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +7 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/duration.d.ts +3 -0
- package/dist/utils/duration.d.ts.map +1 -0
- package/dist/utils/duration.js +17 -0
- package/dist/utils/duration.js.map +1 -0
- package/dist/utils/number.d.ts +3 -0
- package/dist/utils/number.d.ts.map +1 -0
- package/dist/utils/number.js +5 -0
- package/dist/utils/number.js.map +1 -0
- package/docs/bundled/extensions/agent.md +14 -12
- package/docs/bundled/extensions/cached-compaction.md +13 -4
- package/docs/bundled/extensions/deepwiki.md +3 -1
- package/docs/bundled/extensions/statusline.md +1 -1
- package/docs/bundled/tasks.md +15 -14
- package/docs/extensions.md +26 -10
- package/docs/packages.md +5 -3
- package/docs/sdk.md +3 -3
- package/docs/session-format.md +28 -24
- package/docs/settings.md +11 -0
- package/docs/skills.md +23 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/schemas/settings.schema.json +36 -0
- package/dist/bundle/chunks/chunk-FSJ45CRP.js +0 -229
- package/dist/bundle/chunks/chunk-W3FIUMGM.js +0 -1501
- package/dist/core/tasks/history.d.ts +0 -4
- package/dist/core/tasks/history.d.ts.map +0 -1
- package/dist/core/tasks/history.js +0 -131
- package/dist/core/tasks/history.js.map +0 -1
- package/dist/extensions/agent/runner.d.ts +0 -24
- package/dist/extensions/agent/runner.d.ts.map +0 -1
- package/dist/extensions/agent/runner.js +0 -274
- package/dist/extensions/agent/runner.js.map +0 -1
- package/dist/extensions/deepwiki/http.d.ts +0 -13
- package/dist/extensions/deepwiki/http.d.ts.map +0 -1
- package/dist/extensions/deepwiki/http.js +0 -88
- package/dist/extensions/deepwiki/http.js.map +0 -1
- package/dist/extensions/tasks/ui/task-view.d.ts +0 -13
- package/dist/extensions/tasks/ui/task-view.d.ts.map +0 -1
- package/dist/extensions/tasks/ui/task-view.js +0 -20
- package/dist/extensions/tasks/ui/task-view.js.map +0 -1
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
|
2
2
|
import type { CustomMessage } from "../messages.ts";
|
|
3
|
-
import type {
|
|
3
|
+
import type { TaskDeliveryLedger } from "./types.ts";
|
|
4
4
|
export interface TaskDeliveryOptions {
|
|
5
|
-
service():
|
|
5
|
+
service(): TaskDeliveryLedger;
|
|
6
6
|
canDeliver(): boolean;
|
|
7
7
|
deliver(message: CustomMessage, waitForPersistence: () => Promise<void>): Promise<void>;
|
|
8
8
|
warn(event: string, message: string): void;
|
|
9
9
|
}
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Sole owner of delivery policy: pausing, failure tracking, the in-flight completion and wait
|
|
12
|
+
* receipts. The runtime only answers per-record questions through TaskDeliveryLedger.
|
|
13
|
+
*/
|
|
11
14
|
export declare class TaskDelivery {
|
|
12
15
|
private readonly options;
|
|
13
16
|
private disposed;
|
|
@@ -32,7 +35,11 @@ export declare class TaskDelivery {
|
|
|
32
35
|
queueCleared(): void;
|
|
33
36
|
/** Acknowledge only successful appends, using identity even when metadata was rewritten. */
|
|
34
37
|
messagePersisted(message: AgentMessage): void;
|
|
35
|
-
|
|
38
|
+
/**
|
|
39
|
+
* A wait observed a settled background task. The runtime still holds it; take over that hold
|
|
40
|
+
* until the wait's tool result is persisted, then acknowledge it instead of notifying.
|
|
41
|
+
*/
|
|
42
|
+
bindWait(service: TaskDeliveryLedger, toolCallId: string, taskId: string): void;
|
|
36
43
|
private acknowledgeWait;
|
|
37
44
|
private releaseWaits;
|
|
38
45
|
dispose(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/delivery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/delivery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,WAAW,mBAAmB;IACnC,OAAO,IAAI,kBAAkB,CAAC;IAC9B,UAAU,IAAI,OAAO,CAAC;IACtB,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxF,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAUD;;;GAGG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,KAAK,CAAC,CAAgC;IAC9C,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuF;gBACjG,OAAO,EAAE,mBAAmB;IAGxC,OAAO,KAAK,OAAO,GAElB;IACD,OAAO,CAAC,IAAI;IAGZ,sEAAsE;IACtE,KAAK,IAAI,MAAM,IAAI;IAWnB,KAAK,IAAI,IAAI;IAKb,QAAQ,IAAI,IAAI;IAWhB,OAAO,CAAC,UAAU;YAMJ,KAAK;IAiDnB,mFAAmF;IACnF,cAAc,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAK3C,gFAAgF;IAChF,UAAU,IAAI,IAAI;IAQlB,YAAY,IAAI,IAAI;IAIpB,4FAA4F;IAC5F,gBAAgB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAU7C;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAK/E,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,YAAY;IAKpB,OAAO,IAAI,IAAI;CAOf"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { taskCompletionMessage } from "./presentation.js";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Sole owner of delivery policy: pausing, failure tracking, the in-flight completion and wait
|
|
4
|
+
* receipts. The runtime only answers per-record questions through TaskDeliveryLedger.
|
|
5
|
+
*/
|
|
4
6
|
export class TaskDelivery {
|
|
5
7
|
constructor(options) {
|
|
6
8
|
this.disposed = false;
|
|
@@ -18,14 +20,12 @@ export class TaskDelivery {
|
|
|
18
20
|
/** Nestable across asynchronous preflight and service replacement. */
|
|
19
21
|
pause() {
|
|
20
22
|
this.pauses++;
|
|
21
|
-
const releaseService = this.service.pause();
|
|
22
23
|
let released = false;
|
|
23
24
|
return () => {
|
|
24
25
|
if (released)
|
|
25
26
|
return;
|
|
26
27
|
released = true;
|
|
27
28
|
this.pauses--;
|
|
28
|
-
releaseService();
|
|
29
29
|
this.schedule();
|
|
30
30
|
};
|
|
31
31
|
}
|
|
@@ -124,11 +124,11 @@ export class TaskDelivery {
|
|
|
124
124
|
if (message.role === "toolResult")
|
|
125
125
|
this.acknowledgeWait(message.toolCallId);
|
|
126
126
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
/**
|
|
128
|
+
* A wait observed a settled background task. The runtime still holds it; take over that hold
|
|
129
|
+
* until the wait's tool result is persisted, then acknowledge it instead of notifying.
|
|
130
|
+
*/
|
|
131
|
+
bindWait(service, toolCallId, taskId) {
|
|
132
132
|
this.waits.get(toolCallId)?.release();
|
|
133
133
|
this.waits.set(toolCallId, { service, taskId, release: service.holdDelivery(taskId) });
|
|
134
134
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery.js","sourceRoot":"","sources":["../../../src/core/tasks/delivery.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAiB5C,+EAA+E;AAC/E,MAAM,OAAO,YAAY;IAQxB,YAAY,OAA4B;QANhC,aAAQ,GAAG,KAAK,CAAC;QACjB,WAAM,GAAG,CAAC,CAAC;QAGF,aAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;QAC7B,UAAK,GAAG,IAAI,GAAG,EAAqE,CAAC;QAErG,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;IACD,IAAY,OAAO;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;IAC/B,CAAC;IACO,IAAI,CAAC,KAAa,EAAE,OAAe;QAC1C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IACD,sEAAsE;IACtE,KAAK;QACJ,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC5C,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,OAAO,GAAG,EAAE;YACX,IAAI,QAAQ;gBAAE,OAAO;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,cAAc,EAAE,CAAC;YACjB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjB,CAAC,CAAC;IACH,CAAC;IAED,KAAK;QACJ,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,EAAE,CAAC;IACjB,CAAC;IAED,QAAQ;QACP,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QACzD,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;YACvB,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAC5B,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,mEAAmE,CAAC,CAC/F,CAAC;QACH,CAAC,EAAE,CAAC,CAAC,CAAC;QACN,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IACtB,CAAC;IAEO,UAAU,CAAC,OAAoB;QACtC,OAAO,CACN,CAAC,IAAI,CAAC,QAAQ,IAAI,OAAO,KAAK,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,CAC/G,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,KAAK;QAClB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC;YAAE,OAAO;QACvD,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAChE,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ;gBAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;oBAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACjF,CAAC;QACD,MAAM,IAAI,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QACxF,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,OAAO;QAChD,sFAAsF;QACtF,iDAAiD;QACjD,MAAM,QAAQ,GAAa;YAC1B,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,OAAO;YACP,OAAO;YACP,KAAK,EAAE,SAAS;SAChB,CAAC;QACF,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,aAAsB,CAAC;QAC3B,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CACzB,QAAQ,CAAC,OAAO,EAChB,GAAG,EAAE,CACJ,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACrC,IAAI,QAAQ,CAAC,KAAK,KAAK,WAAW;oBAAE,OAAO,EAAE,CAAC;;oBACzC,QAAQ,CAAC,MAAM,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;YAC5C,CAAC,CAAC,CACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,aAAa,GAAG,KAAK,CAAC;QACvB,CAAC;gBAAS,CAAC;YACV,IAAI,QAAQ,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;gBACpC,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACrC,IAAI,OAAO,KAAK,IAAI,CAAC,OAAO;oBAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACzD,MAAM,MAAM,GAAG,aAAa,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,aAAa,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClF,IAAI,CAAC,IAAI,CACR,eAAe,EACf,6CAA6C,IAAI,CAAC,EAAE,GAAG,MAAM,oCAAoC,CACjG,CAAC;YACH,CAAC;YACD,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;YAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;YAC7B,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACzG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC;IACF,CAAC;IAED,mFAAmF;IACnF,cAAc,CAAC,OAAqB;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,IAAI,QAAQ,EAAE,OAAO,KAAK,OAAO,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS;YAAE,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAC;IAC/F,CAAC;IAED,gFAAgF;IAChF,UAAU;QACT,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,IAAI,QAAQ,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;YACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC,CAAC;QAChF,CAAC;IACF,CAAC;IAED,YAAY;QACX,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;IACjG,CAAC;IAED,4FAA4F;IAC5F,gBAAgB,CAAC,OAAqB;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC/B,IAAI,QAAQ,EAAE,OAAO,KAAK,OAAO,IAAI,QAAQ,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;YACrE,QAAQ,CAAC,KAAK,GAAG,WAAW,CAAC;YAC7B,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;YAC5C,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;QAC5B,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,YAAY;YAAE,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7E,CAAC;IAED,WAAW,CAAC,UAAkB,EAAE,MAAc;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,OAAO;QACvE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IAEO,eAAe,CAAC,UAAkB;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC9B,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC9C,OAAO,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;IAEO,YAAY;QACnB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,OAAO,CAAC,OAAO,EAAE,CAAC;QAC7D,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IAED,OAAO;QACN,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC;QACrE,IAAI,IAAI,CAAC,KAAK;YAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;IACxB,CAAC;CACD","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { CustomMessage } from \"../messages.ts\";\nimport { taskCompletionMessage } from \"./presentation.ts\";\nimport type { TaskRuntime } from \"./runtime.ts\";\nimport { isTaskTerminal } from \"./types.ts\";\n\nexport interface TaskDeliveryOptions {\n\tservice(): TaskRuntime;\n\tcanDeliver(): boolean;\n\tdeliver(message: CustomMessage, waitForPersistence: () => Promise<void>): Promise<void>;\n\twarn(event: string, message: string): void;\n}\ninterface Delivery {\n\tid: string;\n\tservice: TaskRuntime;\n\t/** Agent-core preserves message identity; extension rewrites mutate it in place. */\n\tmessage: CustomMessage;\n\tphase: \"pending\" | \"started\" | \"persisted\";\n\tqueued?: { resolve(): void; reject(reason: Error): void };\n}\n\n/** Result delivery is independent of execution handles and retained output. */\nexport class TaskDelivery {\n\tprivate readonly options: TaskDeliveryOptions;\n\tprivate disposed = false;\n\tprivate pauses = 0;\n\tprivate timer?: ReturnType<typeof setTimeout>;\n\tprivate delivery?: Delivery;\n\tprivate readonly failures = new Set<string>();\n\tprivate readonly waits = new Map<string, { service: TaskRuntime; taskId: string; release(): void }>();\n\tconstructor(options: TaskDeliveryOptions) {\n\t\tthis.options = options;\n\t}\n\tprivate get service(): TaskRuntime {\n\t\treturn this.options.service();\n\t}\n\tprivate warn(event: string, message: string): void {\n\t\tthis.options.warn(event, message);\n\t}\n\t/** Nestable across asynchronous preflight and service replacement. */\n\tpause(): () => void {\n\t\tthis.pauses++;\n\t\tconst releaseService = this.service.pause();\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tthis.pauses--;\n\t\t\treleaseService();\n\t\t\tthis.schedule();\n\t\t};\n\t}\n\n\tretry(): void {\n\t\tthis.failures.clear();\n\t\tthis.schedule();\n\t}\n\n\tschedule(): void {\n\t\tif (this.disposed || this.timer || this.delivery) return;\n\t\tthis.timer = setTimeout(() => {\n\t\t\tthis.timer = undefined;\n\t\t\tvoid this.drain().catch(() =>\n\t\t\t\tthis.warn(\"task_delivery\", \"Background notification drain failed; delivery was not confirmed.\"),\n\t\t\t);\n\t\t}, 0);\n\t\tthis.timer.unref?.();\n\t}\n\n\tprivate canDeliver(service: TaskRuntime): boolean {\n\t\treturn (\n\t\t\t!this.disposed && service === this.service && service.enabled && this.pauses === 0 && this.options.canDeliver()\n\t\t);\n\t}\n\n\tprivate async drain(): Promise<void> {\n\t\tconst service = this.service;\n\t\tif (this.delivery || !this.canDeliver(service)) return;\n\t\tif (this.failures.size) {\n\t\t\tconst retained = new Set(service.list().map((task) => task.id));\n\t\t\tfor (const id of this.failures) if (!retained.has(id)) this.failures.delete(id);\n\t\t}\n\t\tconst task = service.pendingNotifications().find((task) => !this.failures.has(task.id));\n\t\tif (!task) return;\n\t\tconst message = taskCompletionMessage(task);\n\t\tif (!service.claimNotification(task.id)) return;\n\t\t// Exactly one completion may be in flight, whether queued for steering or running its\n\t\t// own turn; there is no separate claim registry.\n\t\tconst delivery: Delivery = {\n\t\t\tid: task.id,\n\t\t\tservice,\n\t\t\tmessage,\n\t\t\tphase: \"pending\",\n\t\t};\n\t\tthis.delivery = delivery;\n\t\tlet deliveryError: unknown;\n\t\ttry {\n\t\t\tawait this.options.deliver(\n\t\t\t\tdelivery.message,\n\t\t\t\t() =>\n\t\t\t\t\tnew Promise<void>((resolve, reject) => {\n\t\t\t\t\t\tif (delivery.phase === \"persisted\") resolve();\n\t\t\t\t\t\telse delivery.queued = { resolve, reject };\n\t\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tdeliveryError = error;\n\t\t} finally {\n\t\t\tif (delivery.phase !== \"persisted\") {\n\t\t\t\tservice.releaseNotification(task.id);\n\t\t\t\tif (service === this.service) this.failures.add(task.id);\n\t\t\t\tconst reason = deliveryError instanceof Error ? `: ${deliveryError.message}` : \"\";\n\t\t\t\tthis.warn(\n\t\t\t\t\t\"task_delivery\",\n\t\t\t\t\t`Background completion delivery failed for ${task.id}${reason}; it will retry on the next input.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.delivery = undefined;\n\t\t\tconst current = this.service;\n\t\t\tif (this.canDeliver(current) && current.pendingNotifications().some((task) => !this.failures.has(task.id)))\n\t\t\t\tthis.schedule();\n\t\t}\n\t}\n\n\t/** Record dequeueing before message hooks can fail or rewrite the notification. */\n\tmessageStarted(message: AgentMessage): void {\n\t\tconst delivery = this.delivery;\n\t\tif (delivery?.message === message && delivery.phase === \"pending\") delivery.phase = \"started\";\n\t}\n\n\t/** A queued message that was never emitted remains claimed for the next run. */\n\tagentEnded(): void {\n\t\tthis.releaseWaits();\n\t\tconst delivery = this.delivery;\n\t\tif (delivery?.phase === \"started\") {\n\t\t\tdelivery.queued?.reject(new Error(\"the completion message was not persisted\"));\n\t\t}\n\t}\n\n\tqueueCleared(): void {\n\t\tthis.delivery?.queued?.reject(new Error(\"the completion message was dequeued before delivery\"));\n\t}\n\n\t/** Acknowledge only successful appends, using identity even when metadata was rewritten. */\n\tmessagePersisted(message: AgentMessage): void {\n\t\tconst delivery = this.delivery;\n\t\tif (delivery?.message === message && delivery.phase !== \"persisted\") {\n\t\t\tdelivery.phase = \"persisted\";\n\t\t\tdelivery.service.markDelivered(delivery.id);\n\t\t\tdelivery.queued?.resolve();\n\t\t}\n\t\tif (message.role === \"toolResult\") this.acknowledgeWait(message.toolCallId);\n\t}\n\n\tprepareWait(toolCallId: string, taskId: string): void {\n\t\tconst service = this.service;\n\t\tconst task = service.get(taskId);\n\t\tif (task.mode !== \"background\" || !isTaskTerminal(task.status)) return;\n\t\tthis.waits.get(toolCallId)?.release();\n\t\tthis.waits.set(toolCallId, { service, taskId, release: service.holdDelivery(taskId) });\n\t}\n\n\tprivate acknowledgeWait(toolCallId: string): void {\n\t\tconst receipt = this.waits.get(toolCallId);\n\t\tif (!receipt) return;\n\t\tthis.waits.delete(toolCallId);\n\t\treceipt.service.markDelivered(receipt.taskId);\n\t\treceipt.release();\n\t}\n\n\tprivate releaseWaits(): void {\n\t\tfor (const receipt of this.waits.values()) receipt.release();\n\t\tthis.waits.clear();\n\t}\n\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t\tthis.releaseWaits();\n\t\tthis.delivery?.queued?.reject(new Error(\"the session was disposed\"));\n\t\tif (this.timer) clearTimeout(this.timer);\n\t\tthis.timer = undefined;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"delivery.js","sourceRoot":"","sources":["../../../src/core/tasks/delivery.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport type { CustomMessage } from \"../messages.ts\";\nimport { taskCompletionMessage } from \"./presentation.ts\";\nimport type { TaskDeliveryLedger } from \"./types.ts\";\n\nexport interface TaskDeliveryOptions {\n\tservice(): TaskDeliveryLedger;\n\tcanDeliver(): boolean;\n\tdeliver(message: CustomMessage, waitForPersistence: () => Promise<void>): Promise<void>;\n\twarn(event: string, message: string): void;\n}\ninterface Delivery {\n\tid: string;\n\tservice: TaskDeliveryLedger;\n\t/** Agent-core preserves message identity; extension rewrites mutate it in place. */\n\tmessage: CustomMessage;\n\tphase: \"pending\" | \"started\" | \"persisted\";\n\tqueued?: { resolve(): void; reject(reason: Error): void };\n}\n\n/**\n * Sole owner of delivery policy: pausing, failure tracking, the in-flight completion and wait\n * receipts. The runtime only answers per-record questions through TaskDeliveryLedger.\n */\nexport class TaskDelivery {\n\tprivate readonly options: TaskDeliveryOptions;\n\tprivate disposed = false;\n\tprivate pauses = 0;\n\tprivate timer?: ReturnType<typeof setTimeout>;\n\tprivate delivery?: Delivery;\n\tprivate readonly failures = new Set<string>();\n\tprivate readonly waits = new Map<string, { service: TaskDeliveryLedger; taskId: string; release(): void }>();\n\tconstructor(options: TaskDeliveryOptions) {\n\t\tthis.options = options;\n\t}\n\tprivate get service(): TaskDeliveryLedger {\n\t\treturn this.options.service();\n\t}\n\tprivate warn(event: string, message: string): void {\n\t\tthis.options.warn(event, message);\n\t}\n\t/** Nestable across asynchronous preflight and service replacement. */\n\tpause(): () => void {\n\t\tthis.pauses++;\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tthis.pauses--;\n\t\t\tthis.schedule();\n\t\t};\n\t}\n\n\tretry(): void {\n\t\tthis.failures.clear();\n\t\tthis.schedule();\n\t}\n\n\tschedule(): void {\n\t\tif (this.disposed || this.timer || this.delivery) return;\n\t\tthis.timer = setTimeout(() => {\n\t\t\tthis.timer = undefined;\n\t\t\tvoid this.drain().catch(() =>\n\t\t\t\tthis.warn(\"task_delivery\", \"Background notification drain failed; delivery was not confirmed.\"),\n\t\t\t);\n\t\t}, 0);\n\t\tthis.timer.unref?.();\n\t}\n\n\tprivate canDeliver(service: TaskDeliveryLedger): boolean {\n\t\treturn (\n\t\t\t!this.disposed && service === this.service && service.enabled && this.pauses === 0 && this.options.canDeliver()\n\t\t);\n\t}\n\n\tprivate async drain(): Promise<void> {\n\t\tconst service = this.service;\n\t\tif (this.delivery || !this.canDeliver(service)) return;\n\t\tif (this.failures.size) {\n\t\t\tconst retained = new Set(service.list().map((task) => task.id));\n\t\t\tfor (const id of this.failures) if (!retained.has(id)) this.failures.delete(id);\n\t\t}\n\t\tconst task = service.pendingNotifications().find((task) => !this.failures.has(task.id));\n\t\tif (!task) return;\n\t\tconst message = taskCompletionMessage(task);\n\t\tif (!service.claimNotification(task.id)) return;\n\t\t// Exactly one completion may be in flight, whether queued for steering or running its\n\t\t// own turn; there is no separate claim registry.\n\t\tconst delivery: Delivery = {\n\t\t\tid: task.id,\n\t\t\tservice,\n\t\t\tmessage,\n\t\t\tphase: \"pending\",\n\t\t};\n\t\tthis.delivery = delivery;\n\t\tlet deliveryError: unknown;\n\t\ttry {\n\t\t\tawait this.options.deliver(\n\t\t\t\tdelivery.message,\n\t\t\t\t() =>\n\t\t\t\t\tnew Promise<void>((resolve, reject) => {\n\t\t\t\t\t\tif (delivery.phase === \"persisted\") resolve();\n\t\t\t\t\t\telse delivery.queued = { resolve, reject };\n\t\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tdeliveryError = error;\n\t\t} finally {\n\t\t\tif (delivery.phase !== \"persisted\") {\n\t\t\t\tservice.releaseNotification(task.id);\n\t\t\t\tif (service === this.service) this.failures.add(task.id);\n\t\t\t\tconst reason = deliveryError instanceof Error ? `: ${deliveryError.message}` : \"\";\n\t\t\t\tthis.warn(\n\t\t\t\t\t\"task_delivery\",\n\t\t\t\t\t`Background completion delivery failed for ${task.id}${reason}; it will retry on the next input.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.delivery = undefined;\n\t\t\tconst current = this.service;\n\t\t\tif (this.canDeliver(current) && current.pendingNotifications().some((task) => !this.failures.has(task.id)))\n\t\t\t\tthis.schedule();\n\t\t}\n\t}\n\n\t/** Record dequeueing before message hooks can fail or rewrite the notification. */\n\tmessageStarted(message: AgentMessage): void {\n\t\tconst delivery = this.delivery;\n\t\tif (delivery?.message === message && delivery.phase === \"pending\") delivery.phase = \"started\";\n\t}\n\n\t/** A queued message that was never emitted remains claimed for the next run. */\n\tagentEnded(): void {\n\t\tthis.releaseWaits();\n\t\tconst delivery = this.delivery;\n\t\tif (delivery?.phase === \"started\") {\n\t\t\tdelivery.queued?.reject(new Error(\"the completion message was not persisted\"));\n\t\t}\n\t}\n\n\tqueueCleared(): void {\n\t\tthis.delivery?.queued?.reject(new Error(\"the completion message was dequeued before delivery\"));\n\t}\n\n\t/** Acknowledge only successful appends, using identity even when metadata was rewritten. */\n\tmessagePersisted(message: AgentMessage): void {\n\t\tconst delivery = this.delivery;\n\t\tif (delivery?.message === message && delivery.phase !== \"persisted\") {\n\t\t\tdelivery.phase = \"persisted\";\n\t\t\tdelivery.service.markDelivered(delivery.id);\n\t\t\tdelivery.queued?.resolve();\n\t\t}\n\t\tif (message.role === \"toolResult\") this.acknowledgeWait(message.toolCallId);\n\t}\n\n\t/**\n\t * A wait observed a settled background task. The runtime still holds it; take over that hold\n\t * until the wait's tool result is persisted, then acknowledge it instead of notifying.\n\t */\n\tbindWait(service: TaskDeliveryLedger, toolCallId: string, taskId: string): void {\n\t\tthis.waits.get(toolCallId)?.release();\n\t\tthis.waits.set(toolCallId, { service, taskId, release: service.holdDelivery(taskId) });\n\t}\n\n\tprivate acknowledgeWait(toolCallId: string): void {\n\t\tconst receipt = this.waits.get(toolCallId);\n\t\tif (!receipt) return;\n\t\tthis.waits.delete(toolCallId);\n\t\treceipt.service.markDelivered(receipt.taskId);\n\t\treceipt.release();\n\t}\n\n\tprivate releaseWaits(): void {\n\t\tfor (const receipt of this.waits.values()) receipt.release();\n\t\tthis.waits.clear();\n\t}\n\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t\tthis.releaseWaits();\n\t\tthis.delivery?.queued?.reject(new Error(\"the session was disposed\"));\n\t\tif (this.timer) clearTimeout(this.timer);\n\t\tthis.timer = undefined;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Usage } from "@earendil-works/pi-ai/compat";
|
|
2
|
+
import type { TaskRecord } from "./record.ts";
|
|
3
|
+
import type { TaskControl, TaskExecution, TaskSnapshot, TaskToolOutcome } from "./types.ts";
|
|
4
|
+
/** The runtime services one execution needs; it never reaches into the runtime itself. */
|
|
5
|
+
export interface ExecutionHost {
|
|
6
|
+
readonly closed: boolean;
|
|
7
|
+
emit(): void;
|
|
8
|
+
/** Synchronous persistence before terminal observers or notifications. */
|
|
9
|
+
settle(task: TaskSnapshot, usage: Usage | undefined): void;
|
|
10
|
+
/** The execution settled and holds no slot, parent listener or caller any more. */
|
|
11
|
+
released(execution: Execution<unknown>): void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* One live task: its caller, controller, parent link and executor callbacks.
|
|
15
|
+
*
|
|
16
|
+
* A caller may be handed off to the background whenever no executor preflight is in
|
|
17
|
+
* progress: before `run` starts (queued) or after the executor calls `accept()`.
|
|
18
|
+
*/
|
|
19
|
+
export declare class Execution<T> {
|
|
20
|
+
readonly record: TaskRecord;
|
|
21
|
+
readonly concurrency?: {
|
|
22
|
+
key: string;
|
|
23
|
+
limit: number;
|
|
24
|
+
};
|
|
25
|
+
readonly caller: Promise<TaskToolOutcome<T>>;
|
|
26
|
+
readonly done: Promise<void>;
|
|
27
|
+
readonly control: TaskControl<T>;
|
|
28
|
+
private readonly host;
|
|
29
|
+
private readonly run;
|
|
30
|
+
private readonly controller;
|
|
31
|
+
private readonly modeListeners;
|
|
32
|
+
private resolveCaller;
|
|
33
|
+
private rejectCaller;
|
|
34
|
+
private resolveDone;
|
|
35
|
+
private onUpdate?;
|
|
36
|
+
private releaseParentSignal;
|
|
37
|
+
private usage?;
|
|
38
|
+
private started;
|
|
39
|
+
private accepted;
|
|
40
|
+
private handedOff;
|
|
41
|
+
private detachRequested;
|
|
42
|
+
/** The executor's `run` promise once started. */
|
|
43
|
+
private running?;
|
|
44
|
+
constructor(host: ExecutionHost, record: TaskRecord, execution: TaskExecution<T>);
|
|
45
|
+
get task(): Readonly<TaskSnapshot>;
|
|
46
|
+
get aborted(): boolean;
|
|
47
|
+
/** Executor preflight never races a handoff; queued work has not begun any. */
|
|
48
|
+
private get handoffAllowed();
|
|
49
|
+
/** Waiting for a concurrency slot: registered, but `run` has not started. */
|
|
50
|
+
get queued(): boolean;
|
|
51
|
+
get detachable(): boolean;
|
|
52
|
+
/** Stop forwarding to the launching tool call: parent cancellation and progress no longer reach it. */
|
|
53
|
+
releaseParent(): void;
|
|
54
|
+
start(): void;
|
|
55
|
+
handoff(): void;
|
|
56
|
+
requestDetach(): void;
|
|
57
|
+
completeDetach(): void;
|
|
58
|
+
cancel(): boolean;
|
|
59
|
+
private onModeChange;
|
|
60
|
+
private accept;
|
|
61
|
+
/**
|
|
62
|
+
* Hand off unless `run` has already settled. A reaction on an already settled promise is
|
|
63
|
+
* queued at once, ahead of the pending-check below whatever the promise's chain depth, so
|
|
64
|
+
* the outcome never depends on how `start()` chains its own handlers.
|
|
65
|
+
*/
|
|
66
|
+
private handoffIfRunning;
|
|
67
|
+
private publish;
|
|
68
|
+
private attachOutput;
|
|
69
|
+
private finish;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=execution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/execution.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAU1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAEX,WAAW,EACX,aAAa,EAGb,YAAY,EAGZ,eAAe,EAEf,MAAM,YAAY,CAAC;AAEpB,0FAA0F;AAC1F,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,IAAI,IAAI,IAAI,CAAC;IACb,0EAA0E;IAC1E,MAAM,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,GAAG,IAAI,CAAC;IAC3D,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC9C;AAeD;;;;;GAKG;AACH,qBAAa,SAAS,CAAC,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAA0B;IAC9C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyB;IACpD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAuC;IACrE,OAAO,CAAC,aAAa,CAAyC;IAC9D,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,QAAQ,CAAC,CAAuC;IACxD,OAAO,CAAC,mBAAmB,CAAwB;IACnD,OAAO,CAAC,KAAK,CAAC,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,eAAe,CAAU;IACjC,iDAAiD;IACjD,OAAO,CAAC,OAAO,CAAC,CAA6B;gBAEjC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC;IAuChF,IAAI,IAAI,IAAI,QAAQ,CAAC,YAAY,CAAC,CAEjC;IAED,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,+EAA+E;IAC/E,OAAO,KAAK,cAAc,GAEzB;IAED,6EAA6E;IAC7E,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,uGAAuG;IACvG,aAAa,IAAI,IAAI;IAMrB,KAAK,IAAI,IAAI;IAsBb,OAAO,IAAI,IAAI;IAoBf,aAAa,IAAI,IAAI;IAQrB,cAAc,IAAI,IAAI;IAWtB,MAAM,IAAI,OAAO;IAWjB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,MAAM;IAUd;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,OAAO;IAiBf,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,MAAM;CAoDd"}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { boundFacts, boundTaskText, boundText, errorText, resultText, TASK_ERROR_BYTES, TASK_PATH_BYTES, } from "./output.js";
|
|
2
|
+
function prependText(text, result) {
|
|
3
|
+
return {
|
|
4
|
+
text: boundText(result?.text ? `${text}\n${result.text}` : text),
|
|
5
|
+
truncated: result?.truncated ?? false,
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
/** Terminal rows replace launch rows with the same label and append new ones. */
|
|
9
|
+
function mergeFacts(base = [], terminal) {
|
|
10
|
+
const labels = new Set(terminal.map(([label]) => label));
|
|
11
|
+
return boundFacts([...base.filter(([label]) => !labels.has(label)), ...terminal]);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* One live task: its caller, controller, parent link and executor callbacks.
|
|
15
|
+
*
|
|
16
|
+
* A caller may be handed off to the background whenever no executor preflight is in
|
|
17
|
+
* progress: before `run` starts (queued) or after the executor calls `accept()`.
|
|
18
|
+
*/
|
|
19
|
+
export class Execution {
|
|
20
|
+
constructor(host, record, execution) {
|
|
21
|
+
this.controller = new AbortController();
|
|
22
|
+
this.modeListeners = new Set();
|
|
23
|
+
this.releaseParentSignal = () => { };
|
|
24
|
+
this.started = false;
|
|
25
|
+
this.accepted = false;
|
|
26
|
+
this.handedOff = false;
|
|
27
|
+
this.host = host;
|
|
28
|
+
this.record = record;
|
|
29
|
+
this.run = execution.run;
|
|
30
|
+
this.concurrency = execution.concurrency;
|
|
31
|
+
this.detachRequested = execution.background ?? false;
|
|
32
|
+
this.onUpdate = execution.background ? undefined : execution.onUpdate;
|
|
33
|
+
this.caller = new Promise((resolve, reject) => {
|
|
34
|
+
this.resolveCaller = resolve;
|
|
35
|
+
this.rejectCaller = reject;
|
|
36
|
+
});
|
|
37
|
+
this.done = new Promise((resolve) => {
|
|
38
|
+
this.resolveDone = resolve;
|
|
39
|
+
});
|
|
40
|
+
const parent = execution.signal;
|
|
41
|
+
if (parent) {
|
|
42
|
+
const abort = () => {
|
|
43
|
+
if (!this.detachRequested || !this.handoffAllowed)
|
|
44
|
+
this.cancel();
|
|
45
|
+
};
|
|
46
|
+
parent.addEventListener("abort", abort, { once: true });
|
|
47
|
+
this.releaseParentSignal = () => parent.removeEventListener("abort", abort);
|
|
48
|
+
}
|
|
49
|
+
const task = record.task;
|
|
50
|
+
this.control = {
|
|
51
|
+
id: task.id,
|
|
52
|
+
signal: this.controller.signal,
|
|
53
|
+
get mode() {
|
|
54
|
+
return task.mode;
|
|
55
|
+
},
|
|
56
|
+
onModeChange: (listener) => this.onModeChange(listener),
|
|
57
|
+
accept: () => this.accept(),
|
|
58
|
+
publish: (update) => this.publish(update),
|
|
59
|
+
attachOutput: (path, cleanup) => this.attachOutput(path, cleanup),
|
|
60
|
+
cancel: () => {
|
|
61
|
+
this.cancel();
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
get task() {
|
|
66
|
+
return this.record.task;
|
|
67
|
+
}
|
|
68
|
+
get aborted() {
|
|
69
|
+
return this.controller.signal.aborted;
|
|
70
|
+
}
|
|
71
|
+
/** Executor preflight never races a handoff; queued work has not begun any. */
|
|
72
|
+
get handoffAllowed() {
|
|
73
|
+
return !this.started || this.accepted;
|
|
74
|
+
}
|
|
75
|
+
/** Waiting for a concurrency slot: registered, but `run` has not started. */
|
|
76
|
+
get queued() {
|
|
77
|
+
return !this.started && !this.record.settled;
|
|
78
|
+
}
|
|
79
|
+
get detachable() {
|
|
80
|
+
return !this.record.settled && !this.detachRequested && !this.aborted;
|
|
81
|
+
}
|
|
82
|
+
/** Stop forwarding to the launching tool call: parent cancellation and progress no longer reach it. */
|
|
83
|
+
releaseParent() {
|
|
84
|
+
this.releaseParentSignal();
|
|
85
|
+
this.releaseParentSignal = () => { };
|
|
86
|
+
this.onUpdate = undefined;
|
|
87
|
+
}
|
|
88
|
+
start() {
|
|
89
|
+
if (this.started || this.record.settled)
|
|
90
|
+
return;
|
|
91
|
+
if (this.host.closed) {
|
|
92
|
+
this.cancel();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
this.started = true;
|
|
96
|
+
this.record.update((task) => {
|
|
97
|
+
task.status = "running";
|
|
98
|
+
});
|
|
99
|
+
// The rejection handler is installed immediately, including for synchronous preflight throws.
|
|
100
|
+
try {
|
|
101
|
+
this.running = Promise.resolve(this.run(this.control));
|
|
102
|
+
void this.running.then((completion) => this.finish(completion), (error) => this.finish(undefined, error));
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
this.finish(undefined, error);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
handoff() {
|
|
109
|
+
if (!this.handoffAllowed ||
|
|
110
|
+
!this.detachRequested ||
|
|
111
|
+
this.record.settled ||
|
|
112
|
+
this.handedOff ||
|
|
113
|
+
this.host.closed ||
|
|
114
|
+
!this.record.visible ||
|
|
115
|
+
this.aborted)
|
|
116
|
+
return;
|
|
117
|
+
this.handedOff = true;
|
|
118
|
+
this.record.update((task) => {
|
|
119
|
+
task.mode = "background";
|
|
120
|
+
});
|
|
121
|
+
this.releaseParent();
|
|
122
|
+
this.resolveCaller({ kind: "background", task: this.record.snapshot() });
|
|
123
|
+
this.host.emit();
|
|
124
|
+
}
|
|
125
|
+
requestDetach() {
|
|
126
|
+
this.detachRequested = true;
|
|
127
|
+
this.record.update((task) => {
|
|
128
|
+
task.mode = "background";
|
|
129
|
+
});
|
|
130
|
+
if (this.accepted)
|
|
131
|
+
this.releaseParent();
|
|
132
|
+
}
|
|
133
|
+
completeDetach() {
|
|
134
|
+
this.handoff();
|
|
135
|
+
for (const listener of this.modeListeners) {
|
|
136
|
+
try {
|
|
137
|
+
listener(this.task.mode);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
/* Executors own their diagnostics. */
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
cancel() {
|
|
145
|
+
if (this.record.settled || this.aborted)
|
|
146
|
+
return false;
|
|
147
|
+
this.record.update((task) => {
|
|
148
|
+
task.status = "stopping";
|
|
149
|
+
});
|
|
150
|
+
this.controller.abort();
|
|
151
|
+
if (!this.started)
|
|
152
|
+
this.finish(undefined, new Error("Task cancelled before it started."));
|
|
153
|
+
this.host.emit();
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
onModeChange(listener) {
|
|
157
|
+
if (this.record.settled || this.host.closed)
|
|
158
|
+
return () => { };
|
|
159
|
+
this.modeListeners.add(listener);
|
|
160
|
+
return () => {
|
|
161
|
+
this.modeListeners.delete(listener);
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
accept() {
|
|
165
|
+
if (this.record.settled || this.accepted || this.host.closed || this.aborted)
|
|
166
|
+
return;
|
|
167
|
+
this.accepted = true;
|
|
168
|
+
if (this.detachRequested)
|
|
169
|
+
this.releaseParent();
|
|
170
|
+
// An already available final result wins over a handoff, so decide only once the
|
|
171
|
+
// executor's own synchronous code has yielded.
|
|
172
|
+
queueMicrotask(() => this.handoffIfRunning());
|
|
173
|
+
this.host.emit();
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Hand off unless `run` has already settled. A reaction on an already settled promise is
|
|
177
|
+
* queued at once, ahead of the pending-check below whatever the promise's chain depth, so
|
|
178
|
+
* the outcome never depends on how `start()` chains its own handlers.
|
|
179
|
+
*/
|
|
180
|
+
handoffIfRunning() {
|
|
181
|
+
let settled = false;
|
|
182
|
+
const markSettled = () => {
|
|
183
|
+
settled = true;
|
|
184
|
+
};
|
|
185
|
+
this.running?.then(markSettled, markSettled);
|
|
186
|
+
void Promise.resolve().then(() => {
|
|
187
|
+
if (!settled)
|
|
188
|
+
this.handoff();
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
publish(update) {
|
|
192
|
+
if (this.record.settled || this.host.closed)
|
|
193
|
+
return;
|
|
194
|
+
this.record.update((task) => {
|
|
195
|
+
task.result = resultText(update.result);
|
|
196
|
+
if (update.display !== undefined)
|
|
197
|
+
task.display = boundTaskText(update.display);
|
|
198
|
+
});
|
|
199
|
+
if (update.usage !== undefined)
|
|
200
|
+
this.usage = structuredClone(update.usage);
|
|
201
|
+
if (!this.detachRequested && !this.handedOff) {
|
|
202
|
+
try {
|
|
203
|
+
this.onUpdate?.(update.result);
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
/* UI observers cannot stop execution. */
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
this.host.emit();
|
|
210
|
+
}
|
|
211
|
+
attachOutput(path, cleanup) {
|
|
212
|
+
if (this.record.settled) {
|
|
213
|
+
if (cleanup)
|
|
214
|
+
throw new Error("Task execution has settled");
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (this.record.cleanup)
|
|
218
|
+
throw new Error("Managed output is already registered");
|
|
219
|
+
// Never truncate a real filesystem path into a different path.
|
|
220
|
+
if (Buffer.byteLength(path) > TASK_PATH_BYTES)
|
|
221
|
+
throw new Error("Task output path is too large");
|
|
222
|
+
this.record.cleanup = cleanup;
|
|
223
|
+
this.record.update((task) => {
|
|
224
|
+
task.outputPath = path;
|
|
225
|
+
});
|
|
226
|
+
this.host.emit();
|
|
227
|
+
}
|
|
228
|
+
finish(completion, error) {
|
|
229
|
+
const record = this.record;
|
|
230
|
+
if (record.settled)
|
|
231
|
+
return;
|
|
232
|
+
record.settled = true;
|
|
233
|
+
this.modeListeners.clear();
|
|
234
|
+
this.releaseParent();
|
|
235
|
+
const status = completion
|
|
236
|
+
? (completion.status ?? (this.aborted ? "cancelled" : "completed"))
|
|
237
|
+
: this.aborted
|
|
238
|
+
? "cancelled"
|
|
239
|
+
: "failed";
|
|
240
|
+
record.update((task) => {
|
|
241
|
+
task.endedAt = Date.now();
|
|
242
|
+
task.status = status;
|
|
243
|
+
if (completion) {
|
|
244
|
+
task.result = resultText(completion.result);
|
|
245
|
+
if (completion.display !== undefined)
|
|
246
|
+
task.display = boundTaskText(completion.display);
|
|
247
|
+
if (completion.error !== undefined)
|
|
248
|
+
task.error = boundText(completion.error, TASK_ERROR_BYTES);
|
|
249
|
+
if (completion.facts)
|
|
250
|
+
task.facts = mergeFacts(task.facts, completion.facts);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
task.error = errorText(error);
|
|
254
|
+
task.result = prependText(task.error, task.result);
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
let warning;
|
|
258
|
+
try {
|
|
259
|
+
this.host.settle(record.snapshot(), completion?.usage ?? completion?.result.usage ?? this.usage);
|
|
260
|
+
}
|
|
261
|
+
catch (accountingError) {
|
|
262
|
+
const notice = `Usage settlement failed: ${errorText(accountingError)}`;
|
|
263
|
+
warning = notice;
|
|
264
|
+
record.update((task) => {
|
|
265
|
+
task.error = boundText([task.error, notice].filter(Boolean).join("\n"), 2 * TASK_ERROR_BYTES);
|
|
266
|
+
task.result = prependText(notice, task.result);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
this.usage = undefined;
|
|
270
|
+
// Delivery becomes eligible only after settlement is persisted.
|
|
271
|
+
if (this.handedOff)
|
|
272
|
+
record.queueDelivery();
|
|
273
|
+
else
|
|
274
|
+
record.acknowledge();
|
|
275
|
+
if (!this.handedOff) {
|
|
276
|
+
if (!completion)
|
|
277
|
+
this.rejectCaller(error);
|
|
278
|
+
else {
|
|
279
|
+
// The task ledger owns usage; a tool result never carries it a second time.
|
|
280
|
+
const { usage: _usage, ...result } = completion.result;
|
|
281
|
+
if (warning)
|
|
282
|
+
result.content = [{ type: "text", text: warning }, ...result.content];
|
|
283
|
+
this.resolveCaller({ kind: "result", result, status, error: record.task.error });
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
for (const waiter of [...record.waiters])
|
|
287
|
+
waiter();
|
|
288
|
+
this.resolveDone();
|
|
289
|
+
this.host.released(this);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=execution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution.js","sourceRoot":"","sources":["../../../src/core/tasks/execution.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport type { Usage } from \"@earendil-works/pi-ai/compat\";\nimport {\n\tboundFacts,\n\tboundTaskText,\n\tboundText,\n\terrorText,\n\tresultText,\n\tTASK_ERROR_BYTES,\n\tTASK_PATH_BYTES,\n} from \"./output.ts\";\nimport type { TaskRecord } from \"./record.ts\";\nimport type {\n\tTaskCompletion,\n\tTaskControl,\n\tTaskExecution,\n\tTaskFact,\n\tTaskMode,\n\tTaskSnapshot,\n\tTaskTerminalStatus,\n\tTaskText,\n\tTaskToolOutcome,\n\tTaskUpdate,\n} from \"./types.ts\";\n\n/** The runtime services one execution needs; it never reaches into the runtime itself. */\nexport interface ExecutionHost {\n\treadonly closed: boolean;\n\temit(): void;\n\t/** Synchronous persistence before terminal observers or notifications. */\n\tsettle(task: TaskSnapshot, usage: Usage | undefined): void;\n\t/** The execution settled and holds no slot, parent listener or caller any more. */\n\treleased(execution: Execution<unknown>): void;\n}\n\nfunction prependText(text: string, result: TaskText | undefined): TaskText {\n\treturn {\n\t\ttext: boundText(result?.text ? `${text}\\n${result.text}` : text),\n\t\ttruncated: result?.truncated ?? false,\n\t};\n}\n\n/** Terminal rows replace launch rows with the same label and append new ones. */\nfunction mergeFacts(base: readonly TaskFact[] = [], terminal: readonly TaskFact[]): TaskFact[] {\n\tconst labels = new Set(terminal.map(([label]) => label));\n\treturn boundFacts([...base.filter(([label]) => !labels.has(label)), ...terminal]);\n}\n\n/**\n * One live task: its caller, controller, parent link and executor callbacks.\n *\n * A caller may be handed off to the background whenever no executor preflight is in\n * progress: before `run` starts (queued) or after the executor calls `accept()`.\n */\nexport class Execution<T> {\n\treadonly record: TaskRecord;\n\treadonly concurrency?: { key: string; limit: number };\n\treadonly caller: Promise<TaskToolOutcome<T>>;\n\treadonly done: Promise<void>;\n\treadonly control: TaskControl<T>;\n\tprivate readonly host: ExecutionHost;\n\tprivate readonly run: TaskExecution<T>[\"run\"];\n\tprivate readonly controller = new AbortController();\n\tprivate readonly modeListeners = new Set<(mode: TaskMode) => void>();\n\tprivate resolveCaller!: (outcome: TaskToolOutcome<T>) => void;\n\tprivate rejectCaller!: (error: unknown) => void;\n\tprivate resolveDone!: () => void;\n\tprivate onUpdate?: (result: AgentToolResult<T>) => void;\n\tprivate releaseParentSignal: () => void = () => {};\n\tprivate usage?: Usage;\n\tprivate started = false;\n\tprivate accepted = false;\n\tprivate handedOff = false;\n\tprivate detachRequested: boolean;\n\t/** The executor's `run` promise once started. */\n\tprivate running?: Promise<TaskCompletion<T>>;\n\n\tconstructor(host: ExecutionHost, record: TaskRecord, execution: TaskExecution<T>) {\n\t\tthis.host = host;\n\t\tthis.record = record;\n\t\tthis.run = execution.run;\n\t\tthis.concurrency = execution.concurrency;\n\t\tthis.detachRequested = execution.background ?? false;\n\t\tthis.onUpdate = execution.background ? undefined : execution.onUpdate;\n\t\tthis.caller = new Promise<TaskToolOutcome<T>>((resolve, reject) => {\n\t\t\tthis.resolveCaller = resolve;\n\t\t\tthis.rejectCaller = reject;\n\t\t});\n\t\tthis.done = new Promise<void>((resolve) => {\n\t\t\tthis.resolveDone = resolve;\n\t\t});\n\t\tconst parent = execution.signal;\n\t\tif (parent) {\n\t\t\tconst abort = () => {\n\t\t\t\tif (!this.detachRequested || !this.handoffAllowed) this.cancel();\n\t\t\t};\n\t\t\tparent.addEventListener(\"abort\", abort, { once: true });\n\t\t\tthis.releaseParentSignal = () => parent.removeEventListener(\"abort\", abort);\n\t\t}\n\t\tconst task = record.task;\n\t\tthis.control = {\n\t\t\tid: task.id,\n\t\t\tsignal: this.controller.signal,\n\t\t\tget mode() {\n\t\t\t\treturn task.mode;\n\t\t\t},\n\t\t\tonModeChange: (listener) => this.onModeChange(listener),\n\t\t\taccept: () => this.accept(),\n\t\t\tpublish: (update) => this.publish(update),\n\t\t\tattachOutput: (path, cleanup) => this.attachOutput(path, cleanup),\n\t\t\tcancel: () => {\n\t\t\t\tthis.cancel();\n\t\t\t},\n\t\t};\n\t}\n\n\tget task(): Readonly<TaskSnapshot> {\n\t\treturn this.record.task;\n\t}\n\n\tget aborted(): boolean {\n\t\treturn this.controller.signal.aborted;\n\t}\n\n\t/** Executor preflight never races a handoff; queued work has not begun any. */\n\tprivate get handoffAllowed(): boolean {\n\t\treturn !this.started || this.accepted;\n\t}\n\n\t/** Waiting for a concurrency slot: registered, but `run` has not started. */\n\tget queued(): boolean {\n\t\treturn !this.started && !this.record.settled;\n\t}\n\n\tget detachable(): boolean {\n\t\treturn !this.record.settled && !this.detachRequested && !this.aborted;\n\t}\n\n\t/** Stop forwarding to the launching tool call: parent cancellation and progress no longer reach it. */\n\treleaseParent(): void {\n\t\tthis.releaseParentSignal();\n\t\tthis.releaseParentSignal = () => {};\n\t\tthis.onUpdate = undefined;\n\t}\n\n\tstart(): void {\n\t\tif (this.started || this.record.settled) return;\n\t\tif (this.host.closed) {\n\t\t\tthis.cancel();\n\t\t\treturn;\n\t\t}\n\t\tthis.started = true;\n\t\tthis.record.update((task) => {\n\t\t\ttask.status = \"running\";\n\t\t});\n\t\t// The rejection handler is installed immediately, including for synchronous preflight throws.\n\t\ttry {\n\t\t\tthis.running = Promise.resolve(this.run(this.control));\n\t\t\tvoid this.running.then(\n\t\t\t\t(completion) => this.finish(completion),\n\t\t\t\t(error: unknown) => this.finish(undefined, error),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tthis.finish(undefined, error);\n\t\t}\n\t}\n\n\thandoff(): void {\n\t\tif (\n\t\t\t!this.handoffAllowed ||\n\t\t\t!this.detachRequested ||\n\t\t\tthis.record.settled ||\n\t\t\tthis.handedOff ||\n\t\t\tthis.host.closed ||\n\t\t\t!this.record.visible ||\n\t\t\tthis.aborted\n\t\t)\n\t\t\treturn;\n\t\tthis.handedOff = true;\n\t\tthis.record.update((task) => {\n\t\t\ttask.mode = \"background\";\n\t\t});\n\t\tthis.releaseParent();\n\t\tthis.resolveCaller({ kind: \"background\", task: this.record.snapshot() });\n\t\tthis.host.emit();\n\t}\n\n\trequestDetach(): void {\n\t\tthis.detachRequested = true;\n\t\tthis.record.update((task) => {\n\t\t\ttask.mode = \"background\";\n\t\t});\n\t\tif (this.accepted) this.releaseParent();\n\t}\n\n\tcompleteDetach(): void {\n\t\tthis.handoff();\n\t\tfor (const listener of this.modeListeners) {\n\t\t\ttry {\n\t\t\t\tlistener(this.task.mode);\n\t\t\t} catch {\n\t\t\t\t/* Executors own their diagnostics. */\n\t\t\t}\n\t\t}\n\t}\n\n\tcancel(): boolean {\n\t\tif (this.record.settled || this.aborted) return false;\n\t\tthis.record.update((task) => {\n\t\t\ttask.status = \"stopping\";\n\t\t});\n\t\tthis.controller.abort();\n\t\tif (!this.started) this.finish(undefined, new Error(\"Task cancelled before it started.\"));\n\t\tthis.host.emit();\n\t\treturn true;\n\t}\n\n\tprivate onModeChange(listener: (mode: TaskMode) => void): () => void {\n\t\tif (this.record.settled || this.host.closed) return () => {};\n\t\tthis.modeListeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.modeListeners.delete(listener);\n\t\t};\n\t}\n\n\tprivate accept(): void {\n\t\tif (this.record.settled || this.accepted || this.host.closed || this.aborted) return;\n\t\tthis.accepted = true;\n\t\tif (this.detachRequested) this.releaseParent();\n\t\t// An already available final result wins over a handoff, so decide only once the\n\t\t// executor's own synchronous code has yielded.\n\t\tqueueMicrotask(() => this.handoffIfRunning());\n\t\tthis.host.emit();\n\t}\n\n\t/**\n\t * Hand off unless `run` has already settled. A reaction on an already settled promise is\n\t * queued at once, ahead of the pending-check below whatever the promise's chain depth, so\n\t * the outcome never depends on how `start()` chains its own handlers.\n\t */\n\tprivate handoffIfRunning(): void {\n\t\tlet settled = false;\n\t\tconst markSettled = () => {\n\t\t\tsettled = true;\n\t\t};\n\t\tthis.running?.then(markSettled, markSettled);\n\t\tvoid Promise.resolve().then(() => {\n\t\t\tif (!settled) this.handoff();\n\t\t});\n\t}\n\n\tprivate publish(update: TaskUpdate<T>): void {\n\t\tif (this.record.settled || this.host.closed) return;\n\t\tthis.record.update((task) => {\n\t\t\ttask.result = resultText(update.result);\n\t\t\tif (update.display !== undefined) task.display = boundTaskText(update.display);\n\t\t});\n\t\tif (update.usage !== undefined) this.usage = structuredClone(update.usage);\n\t\tif (!this.detachRequested && !this.handedOff) {\n\t\t\ttry {\n\t\t\t\tthis.onUpdate?.(update.result);\n\t\t\t} catch {\n\t\t\t\t/* UI observers cannot stop execution. */\n\t\t\t}\n\t\t}\n\t\tthis.host.emit();\n\t}\n\n\tprivate attachOutput(path: string, cleanup?: () => void | Promise<void>): void {\n\t\tif (this.record.settled) {\n\t\t\tif (cleanup) throw new Error(\"Task execution has settled\");\n\t\t\treturn;\n\t\t}\n\t\tif (this.record.cleanup) throw new Error(\"Managed output is already registered\");\n\t\t// Never truncate a real filesystem path into a different path.\n\t\tif (Buffer.byteLength(path) > TASK_PATH_BYTES) throw new Error(\"Task output path is too large\");\n\t\tthis.record.cleanup = cleanup;\n\t\tthis.record.update((task) => {\n\t\t\ttask.outputPath = path;\n\t\t});\n\t\tthis.host.emit();\n\t}\n\n\tprivate finish(completion: TaskCompletion<T> | undefined, error?: unknown): void {\n\t\tconst record = this.record;\n\t\tif (record.settled) return;\n\t\trecord.settled = true;\n\t\tthis.modeListeners.clear();\n\t\tthis.releaseParent();\n\t\tconst status: TaskTerminalStatus = completion\n\t\t\t? (completion.status ?? (this.aborted ? \"cancelled\" : \"completed\"))\n\t\t\t: this.aborted\n\t\t\t\t? \"cancelled\"\n\t\t\t\t: \"failed\";\n\t\trecord.update((task) => {\n\t\t\ttask.endedAt = Date.now();\n\t\t\ttask.status = status;\n\t\t\tif (completion) {\n\t\t\t\ttask.result = resultText(completion.result);\n\t\t\t\tif (completion.display !== undefined) task.display = boundTaskText(completion.display);\n\t\t\t\tif (completion.error !== undefined) task.error = boundText(completion.error, TASK_ERROR_BYTES);\n\t\t\t\tif (completion.facts) task.facts = mergeFacts(task.facts, completion.facts);\n\t\t\t} else {\n\t\t\t\ttask.error = errorText(error);\n\t\t\t\ttask.result = prependText(task.error, task.result);\n\t\t\t}\n\t\t});\n\t\tlet warning: string | undefined;\n\t\ttry {\n\t\t\tthis.host.settle(record.snapshot(), completion?.usage ?? completion?.result.usage ?? this.usage);\n\t\t} catch (accountingError) {\n\t\t\tconst notice = `Usage settlement failed: ${errorText(accountingError)}`;\n\t\t\twarning = notice;\n\t\t\trecord.update((task) => {\n\t\t\t\ttask.error = boundText([task.error, notice].filter(Boolean).join(\"\\n\"), 2 * TASK_ERROR_BYTES);\n\t\t\t\ttask.result = prependText(notice, task.result);\n\t\t\t});\n\t\t}\n\t\tthis.usage = undefined;\n\t\t// Delivery becomes eligible only after settlement is persisted.\n\t\tif (this.handedOff) record.queueDelivery();\n\t\telse record.acknowledge();\n\t\tif (!this.handedOff) {\n\t\t\tif (!completion) this.rejectCaller(error);\n\t\t\telse {\n\t\t\t\t// The task ledger owns usage; a tool result never carries it a second time.\n\t\t\t\tconst { usage: _usage, ...result } = completion.result;\n\t\t\t\tif (warning) result.content = [{ type: \"text\", text: warning }, ...result.content];\n\t\t\t\tthis.resolveCaller({ kind: \"result\", result, status, error: record.task.error });\n\t\t\t}\n\t\t}\n\t\tfor (const waiter of [...record.waiters]) waiter();\n\t\tthis.resolveDone();\n\t\tthis.host.released(this as Execution<unknown>);\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/format.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/format.ts"],"names":[],"mappings":"AAEA,wBAAgB,YAAY,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,SAAa,GAAG,MAAM,CAEpG"}
|
|
@@ -1,19 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export function formatDuration(ms) {
|
|
3
|
-
if (ms < 500)
|
|
4
|
-
return "<1s";
|
|
5
|
-
const seconds = Math.round(ms / 1000);
|
|
6
|
-
if (seconds < 60)
|
|
7
|
-
return `${seconds}s`;
|
|
8
|
-
const minutes = Math.floor(seconds / 60);
|
|
9
|
-
if (minutes < 60) {
|
|
10
|
-
const remainder = seconds % 60;
|
|
11
|
-
return remainder === 0 ? `${minutes}m` : `${minutes}m ${remainder}s`;
|
|
12
|
-
}
|
|
13
|
-
const hours = Math.floor(minutes / 60);
|
|
14
|
-
const remainder = minutes % 60;
|
|
15
|
-
return remainder === 0 ? `${hours}h` : `${hours}h ${remainder}m`;
|
|
16
|
-
}
|
|
1
|
+
import { formatDuration } from "../../utils/duration.js";
|
|
17
2
|
export function runtimeLabel(task, now = Date.now()) {
|
|
18
3
|
return formatDuration((task.endedAt ?? now) - task.startedAt);
|
|
19
4
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/core/tasks/format.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/core/tasks/format.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,MAAM,UAAU,YAAY,CAAC,IAA6C,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;IAC3F,OAAO,cAAc,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;AAC/D,CAAC","sourcesContent":["import { formatDuration } from \"../../utils/duration.ts\";\n\nexport function runtimeLabel(task: { startedAt: number; endedAt?: number }, now = Date.now()): string {\n\treturn formatDuration((task.endedAt ?? now) - task.startedAt);\n}\n"]}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Shared observation-window limits, the one definition used by the runtime and the tasks tool.
|
|
3
|
+
* Execution timeouts are configured separately by each executor.
|
|
4
|
+
*/
|
|
2
5
|
export declare const TASKS_WAIT_DEFAULT_MS = 20000;
|
|
3
6
|
export declare const TASKS_WAIT_MIN_MS = 1000;
|
|
4
7
|
export declare const TASKS_WAIT_MAX_MS: number;
|
|
8
|
+
/** Floor for a model-requested read slice; the default and ceiling are TASK_READ_BYTES and TASK_RESULT_BYTES. */
|
|
9
|
+
export declare const TASKS_READ_MIN_BYTES = 256;
|
|
10
|
+
/** The wait window the runtime honours: any finite value up to the ceiling, including 0. */
|
|
11
|
+
export declare function boundWaitMs(waitMs: number | undefined): number;
|
|
12
|
+
/** The wait window a tool call runs, which the pending-call renderer also shows. */
|
|
13
|
+
export declare function clampWaitMs(waitMs: number | undefined): number;
|
|
14
|
+
/** The read size a tool call runs. */
|
|
15
|
+
export declare function clampReadBytes(bytes: number | undefined): number;
|
|
5
16
|
//# sourceMappingURL=limits.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/limits.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"limits.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/limits.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAAS,CAAC;AAC5C,eAAO,MAAM,iBAAiB,OAAQ,CAAC;AACvC,eAAO,MAAM,iBAAiB,QAAc,CAAC;AAC7C,iHAAiH;AACjH,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,4FAA4F;AAC5F,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE9D;AAED,oFAAoF;AACpF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE9D;AAED,sCAAsC;AACtC,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAEhE"}
|