@astralyn/pi 1.4.6 → 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 +22 -0
- package/dist/bundle/chunks/{chunk-KDO6L76C.js → chunk-FODCTZXW.js} +4 -4
- package/dist/bundle/chunks/{chunk-EYKC6ESU.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-RBTJBQWX.js → chunk-YJTSOLP2.js} +73 -74
- package/dist/bundle/chunks/{cli-FH77R7JR.js → cli-MEL7SGJD.js} +1 -1
- package/dist/bundle/chunks/{execute-5ZQUS52M.js → execute-4CWRNHPO.js} +1 -1
- package/dist/bundle/chunks/{runtime-R5CMHJ5P.js → runtime-R3X67XMR.js} +1 -1
- package/dist/bundle/chunks/{virtual-modules-KCQU7LOC.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/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/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 +10 -3
- package/dist/core/tasks/execution.d.ts.map +1 -1
- package/dist/core/tasks/execution.js +72 -52
- package/dist/core/tasks/execution.js.map +1 -1
- 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 +6 -12
- package/dist/core/tasks/output.d.ts.map +1 -1
- package/dist/core/tasks/output.js +35 -32
- package/dist/core/tasks/output.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 +14 -14
- package/dist/core/tasks/runtime.d.ts.map +1 -1
- package/dist/core/tasks/runtime.js +111 -93
- package/dist/core/tasks/runtime.js.map +1 -1
- package/dist/core/tasks/session.d.ts +0 -1
- package/dist/core/tasks/session.d.ts.map +1 -1
- package/dist/core/tasks/session.js +7 -8
- 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 +42 -40
- package/dist/core/tasks/store.js.map +1 -1
- package/dist/core/tasks/types.d.ts +96 -17
- package/dist/core/tasks/types.d.ts.map +1 -1
- 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 +18 -26
- 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 +31 -29
- package/dist/core/tools/shell-tool.js.map +1 -1
- package/dist/core/usage-totals.d.ts +3 -0
- package/dist/core/usage-totals.d.ts.map +1 -1
- package/dist/core/usage-totals.js +15 -0
- package/dist/core/usage-totals.js.map +1 -1
- package/dist/extensions/agent/progress.d.ts.map +1 -1
- package/dist/extensions/agent/progress.js +1 -11
- package/dist/extensions/agent/progress.js.map +1 -1
- package/dist/extensions/agent/tool.d.ts.map +1 -1
- package/dist/extensions/agent/tool.js +9 -5
- package/dist/extensions/agent/tool.js.map +1 -1
- package/dist/extensions/agent/worker.d.ts.map +1 -1
- package/dist/extensions/agent/worker.js +3 -5
- package/dist/extensions/agent/worker.js.map +1 -1
- 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 +49 -106
- 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 +4 -13
- package/dist/extensions/tasks/tool/schema.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 +31 -33
- package/dist/extensions/tasks/ui/completion-render.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 +17 -19
- 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 +2 -3
- 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 +163 -131
- package/dist/extensions/tasks/ui/manager.js.map +1 -1
- package/dist/extensions/tasks/ui/model.d.ts +25 -0
- package/dist/extensions/tasks/ui/model.d.ts.map +1 -1
- package/dist/extensions/tasks/ui/model.js +4 -0
- 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 +11 -7
- 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/index.d.ts +1 -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/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/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 +3 -3
- package/docs/bundled/extensions/cached-compaction.md +13 -4
- package/docs/bundled/extensions/deepwiki.md +3 -1
- package/docs/extensions.md +5 -5
- package/docs/packages.md +5 -3
- package/docs/sdk.md +1 -1
- package/docs/session-format.md +1 -1
- 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/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 -8
- package/dist/extensions/tasks/ui/task-view.d.ts.map +0 -1
- package/dist/extensions/tasks/ui/task-view.js +0 -13
- package/dist/extensions/tasks/ui/task-view.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/core/tasks/output.ts"],"names":[],"mappings":"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","sourcesContent":["import { open } from \"node:fs/promises\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport type { TaskFact, TaskInput, TaskText } from \"./types.ts\";\n\nexport const TASK_RESULT_BYTES = 48 * 1024;\nexport const TASK_DETAILS_BYTES = 120 * 1024;\nexport const TASK_READ_BYTES = 8 * 1024;\nexport const TASK_INPUT_BYTES = 24 * 1024;\n/** Task title budget, independent of notification wording and rendering. */\nexport const TASK_TITLE_BYTES = 1024;\nexport const TASK_LABEL_BYTES = 256;\nexport const TASK_FACTS = 16;\nexport const TASK_FACT_BYTES = 1024;\nexport const TASK_ERROR_BYTES = 4096;\nexport const TASK_PATH_BYTES = 8192;\n\nexport function finiteLimit(value: number | undefined, fallback: number, ceiling: number): number {\n\treturn value === undefined || !Number.isFinite(value) ? fallback : Math.max(0, Math.min(ceiling, Math.floor(value)));\n}\n\n/** Both ends are codepoint aligned, including a head read ending inside a character. */\nfunction alignedSlice(buffer: Buffer, start: number, end: number): Buffer {\n\twhile (start < end && (buffer[start]! & 0xc0) === 0x80) start++;\n\tif (end < buffer.length) {\n\t\twhile (end > start && (buffer[end]! & 0xc0) === 0x80) end--;\n\t}\n\t// A concurrently written file can itself end in an incomplete UTF-8 sequence.\n\tlet lead = end - 1;\n\twhile (lead >= start && (buffer[lead]! & 0xc0) === 0x80) lead--;\n\tif (lead >= start) {\n\t\tconst byte = buffer[lead]!;\n\t\tconst width = byte >= 0xf0 ? 4 : byte >= 0xe0 ? 3 : byte >= 0xc0 ? 2 : 1;\n\t\tif (end - lead < width) end = lead;\n\t}\n\treturn buffer.subarray(start, end);\n}\n\nexport function boundText(text: string, bytes = TASK_RESULT_BYTES): string {\n\t// Avoid allocating a buffer proportional to an unbounded source.\n\tconst limit = finiteLimit(bytes, TASK_RESULT_BYTES, TASK_RESULT_BYTES);\n\tconst prefix = text.slice(0, limit + 1);\n\tconst buffer = Buffer.from(prefix);\n\treturn alignedSlice(buffer, 0, Math.min(limit, buffer.length)).toString(\"utf8\");\n}\n\nexport function boundTaskText(text: string, bytes = TASK_RESULT_BYTES): TaskText {\n\tconst bounded = boundText(text, bytes);\n\treturn { text: bounded, truncated: bounded !== text };\n}\n\nexport function boundInput(input: TaskInput): TaskInput {\n\tconst text = boundTaskText(input.text, TASK_INPUT_BYTES);\n\treturn {\n\t\tlabel: boundText(input.label, TASK_LABEL_BYTES),\n\t\ttext: text.text,\n\t\ttruncated: input.truncated || text.truncated,\n\t\t...(input.language ? { language: boundText(input.language, 64) } : {}),\n\t};\n}\n\nexport function boundFacts(facts: readonly TaskFact[]): TaskFact[] {\n\treturn facts\n\t\t.slice(0, TASK_FACTS)\n\t\t.map(([label, value]): TaskFact => [boundText(label, TASK_LABEL_BYTES), boundText(value, TASK_FACT_BYTES)]);\n}\n\n/** The end of a bounded text, codepoint aligned: a command's outcome is at its end. */\nexport function boundTail(text: string, bytes: number): { text: string; truncated: boolean } {\n\tconst buffer = Buffer.from(text);\n\tif (buffer.length <= bytes) return { text, truncated: false };\n\treturn { text: alignedSlice(buffer, buffer.length - bytes, buffer.length).toString(\"utf8\"), truncated: true };\n}\n\n/** The bounded model-readable text of a result; images and private details never enter task state. */\nexport function resultText(result: AgentToolResult<unknown>): TaskText {\n\tlet remaining = TASK_RESULT_BYTES;\n\tconst parts: string[] = [];\n\tlet truncated = false;\n\tfor (const block of result.content) {\n\t\tif (remaining <= 0) {\n\t\t\ttruncated = true;\n\t\t\tbreak;\n\t\t}\n\t\tconst source = block.type === \"text\" ? block.text : \"[Image omitted from task output]\";\n\t\tconst text = boundText(source, remaining);\n\t\tif (block.type !== \"text\" || text !== source) truncated = true;\n\t\tparts.push(text);\n\t\tremaining -= Math.max(1, Buffer.byteLength(text) + 1);\n\t}\n\treturn { text: boundText(parts.join(\"\\n\")), truncated };\n}\n\nexport interface OutputSlice {\n\ttext: string;\n\ttotalBytes: number;\n\ttruncated: boolean;\n\tfromByte: number;\n}\n\n/** Positioned, bounded reads only. The executor owns the path and its cleanup. */\nexport async function readOutputSlice(\n\tpath: string,\n\toptions: { mode?: \"head\" | \"tail\"; bytes?: number; sinceBytes?: number } = {},\n): Promise<OutputSlice> {\n\tconst bytes = finiteLimit(options.bytes, TASK_READ_BYTES, TASK_RESULT_BYTES);\n\tconst file = await open(path, \"r\");\n\ttry {\n\t\tconst { size } = await file.stat();\n\t\tconst since = finiteLimit(options.sinceBytes, 0, Number.MAX_SAFE_INTEGER);\n\t\tconst floor = since > size ? 0 : since;\n\t\tconst start =\n\t\t\toptions.sinceBytes !== undefined\n\t\t\t\t? Math.max(floor, size - bytes)\n\t\t\t\t: options.mode === \"head\"\n\t\t\t\t\t? 0\n\t\t\t\t\t: Math.max(0, size - bytes);\n\t\tconst length = Math.min(bytes, size - start);\n\t\t// One extra byte lets alignment distinguish a complete last codepoint.\n\t\tconst buffer = Buffer.alloc(Math.min(length + 1, size - start));\n\t\tconst { bytesRead } = await file.read(buffer, 0, buffer.length, start);\n\t\tconst slice = alignedSlice(buffer.subarray(0, bytesRead), 0, Math.min(length, bytesRead));\n\t\treturn {\n\t\t\ttext: slice.toString(\"utf8\"),\n\t\t\ttotalBytes: size,\n\t\t\ttruncated: options.sinceBytes !== undefined ? start > floor || slice.length < length : slice.length < size,\n\t\t\tfromByte: start + slice.byteOffset - buffer.byteOffset,\n\t\t};\n\t} finally {\n\t\tawait file.close();\n\t}\n}\n\nexport function sliceText(\n\ttext: string,\n\toptions: { mode?: \"head\" | \"tail\"; bytes?: number; sinceBytes?: number } = {},\n): OutputSlice {\n\tconst buffer = Buffer.from(text);\n\tconst bytes = finiteLimit(options.bytes, TASK_READ_BYTES, TASK_RESULT_BYTES);\n\tconst since = finiteLimit(options.sinceBytes, 0, Number.MAX_SAFE_INTEGER);\n\tconst floor = since > buffer.length ? 0 : since;\n\tconst start =\n\t\toptions.sinceBytes !== undefined\n\t\t\t? Math.max(floor, buffer.length - bytes)\n\t\t\t: options.mode === \"head\"\n\t\t\t\t? 0\n\t\t\t\t: Math.max(0, buffer.length - bytes);\n\tconst slice = alignedSlice(buffer, start, Math.min(buffer.length, start + bytes));\n\treturn {\n\t\ttext: slice.toString(\"utf8\"),\n\t\ttotalBytes: buffer.length,\n\t\ttruncated: slice.length < buffer.length - floor,\n\t\tfromByte: slice.byteOffset - buffer.byteOffset,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../../src/core/tasks/output.ts"],"names":[],"mappings":"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","sourcesContent":["import { open } from \"node:fs/promises\";\nimport type { AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport { finiteLimit } from \"../../utils/number.ts\";\nimport type { TaskFact, TaskInput, TaskReadOptions, TaskText } from \"./types.ts\";\n\nexport const TASK_RESULT_BYTES = 48 * 1024;\nexport const TASK_DETAILS_BYTES = 120 * 1024;\nexport const TASK_READ_BYTES = 8 * 1024;\nexport const TASK_INPUT_BYTES = 24 * 1024;\n/** Task title budget, independent of notification wording and rendering. */\nexport const TASK_TITLE_BYTES = 1024;\nexport const TASK_LABEL_BYTES = 256;\nexport const TASK_FACTS = 16;\nexport const TASK_FACT_BYTES = 1024;\nexport const TASK_ERROR_BYTES = 4096;\nexport const TASK_PATH_BYTES = 8192;\n\n/** A bounded, printable message for any thrown value. */\nexport function errorText(error: unknown, fallback = \"Task execution failed (unprintable error)\"): string {\n\ttry {\n\t\treturn boundText(error instanceof Error ? error.message : String(error), TASK_ERROR_BYTES);\n\t} catch {\n\t\treturn fallback;\n\t}\n}\n\nexport function boundReadBytes(bytes: number | undefined): number {\n\treturn finiteLimit(bytes, TASK_READ_BYTES, TASK_RESULT_BYTES);\n}\n\n/** Both ends are codepoint aligned, including a head read ending inside a character. */\nfunction alignedSlice(buffer: Buffer, start: number, end: number): Buffer {\n\twhile (start < end && (buffer[start]! & 0xc0) === 0x80) start++;\n\tif (end < buffer.length) {\n\t\twhile (end > start && (buffer[end]! & 0xc0) === 0x80) end--;\n\t}\n\t// A concurrently written file can itself end in an incomplete UTF-8 sequence.\n\tlet lead = end - 1;\n\twhile (lead >= start && (buffer[lead]! & 0xc0) === 0x80) lead--;\n\tif (lead >= start) {\n\t\tconst byte = buffer[lead]!;\n\t\tconst width = byte >= 0xf0 ? 4 : byte >= 0xe0 ? 3 : byte >= 0xc0 ? 2 : 1;\n\t\tif (end - lead < width) end = lead;\n\t}\n\treturn buffer.subarray(start, end);\n}\n\nexport function boundText(text: string, bytes = TASK_RESULT_BYTES): string {\n\t// Avoid allocating a buffer proportional to an unbounded source.\n\tconst limit = finiteLimit(bytes, TASK_RESULT_BYTES, TASK_RESULT_BYTES);\n\tconst prefix = text.slice(0, limit + 1);\n\tconst buffer = Buffer.from(prefix);\n\treturn alignedSlice(buffer, 0, Math.min(limit, buffer.length)).toString(\"utf8\");\n}\n\nexport function boundTaskText(text: string, bytes = TASK_RESULT_BYTES): TaskText {\n\tconst bounded = boundText(text, bytes);\n\treturn { text: bounded, truncated: bounded !== text };\n}\n\nexport function boundInput(input: TaskInput): TaskInput {\n\tconst text = boundTaskText(input.text, TASK_INPUT_BYTES);\n\treturn {\n\t\tlabel: boundText(input.label, TASK_LABEL_BYTES),\n\t\ttext: text.text,\n\t\ttruncated: input.truncated || text.truncated,\n\t\t...(input.language ? { language: boundText(input.language, 64) } : {}),\n\t};\n}\n\nexport function boundFacts(facts: readonly TaskFact[]): TaskFact[] {\n\treturn facts\n\t\t.slice(0, TASK_FACTS)\n\t\t.map(([label, value]): TaskFact => [boundText(label, TASK_LABEL_BYTES), boundText(value, TASK_FACT_BYTES)]);\n}\n\n/** The end of a bounded text, codepoint aligned: a command's outcome is at its end. */\nexport function boundTail(text: string, bytes: number): { text: string; truncated: boolean } {\n\tconst buffer = Buffer.from(text);\n\tif (buffer.length <= bytes) return { text, truncated: false };\n\treturn { text: alignedSlice(buffer, buffer.length - bytes, buffer.length).toString(\"utf8\"), truncated: true };\n}\n\n/** The bounded model-readable text of a result; images and private details never enter task state. */\nexport function resultText(result: AgentToolResult<unknown>): TaskText {\n\tlet remaining = TASK_RESULT_BYTES;\n\tconst parts: string[] = [];\n\tlet truncated = false;\n\tfor (const block of result.content) {\n\t\tif (remaining <= 0) {\n\t\t\ttruncated = true;\n\t\t\tbreak;\n\t\t}\n\t\tconst source = block.type === \"text\" ? block.text : \"[Image omitted from task output]\";\n\t\tconst text = boundText(source, remaining);\n\t\tif (block.type !== \"text\" || text !== source) truncated = true;\n\t\tparts.push(text);\n\t\tremaining -= Math.max(1, Buffer.byteLength(text) + 1);\n\t}\n\treturn { text: boundText(parts.join(\"\\n\")), truncated };\n}\n\nexport interface OutputSlice {\n\ttext: string;\n\ttotalBytes: number;\n\ttruncated: boolean;\n\tfromByte: number;\n}\n\n/**\n * The byte window a read covers in an output of `size` bytes. `floor` is the first byte the\n * caller has not seen yet; anything before it never counts as truncated.\n */\nfunction readWindow(size: number, options: TaskReadOptions): { start: number; length: number; floor: number } {\n\tconst bytes = boundReadBytes(options.bytes);\n\tconst since = finiteLimit(options.sinceBytes, 0, Number.MAX_SAFE_INTEGER);\n\tconst floor = since > size ? 0 : since;\n\tconst start =\n\t\toptions.sinceBytes !== undefined\n\t\t\t? Math.max(floor, size - bytes)\n\t\t\t: options.mode === \"head\"\n\t\t\t\t? 0\n\t\t\t\t: Math.max(0, size - bytes);\n\treturn { start, length: Math.min(bytes, size - start), floor };\n}\n\nfunction outputSlice(size: number, floor: number, slice: Buffer, fromByte: number): OutputSlice {\n\treturn { text: slice.toString(\"utf8\"), totalBytes: size, truncated: slice.length < size - floor, fromByte };\n}\n\n/** Positioned, bounded reads only. The executor owns the path and its cleanup. */\nexport async function readOutputSlice(path: string, options: TaskReadOptions = {}): Promise<OutputSlice> {\n\tconst file = await open(path, \"r\");\n\ttry {\n\t\tconst { size } = await file.stat();\n\t\tconst { start, length, floor } = readWindow(size, options);\n\t\t// One extra byte lets alignment distinguish a complete last codepoint.\n\t\tconst buffer = Buffer.alloc(Math.min(length + 1, size - start));\n\t\tconst { bytesRead } = await file.read(buffer, 0, buffer.length, start);\n\t\tconst slice = alignedSlice(buffer.subarray(0, bytesRead), 0, Math.min(length, bytesRead));\n\t\treturn outputSlice(size, floor, slice, start + slice.byteOffset - buffer.byteOffset);\n\t} finally {\n\t\tawait file.close();\n\t}\n}\n\nexport function sliceText(text: string, options: TaskReadOptions = {}): OutputSlice {\n\tconst buffer = Buffer.from(text);\n\tconst { start, length, floor } = readWindow(buffer.length, options);\n\tconst slice = alignedSlice(buffer, start, start + length);\n\treturn outputSlice(buffer.length, floor, slice, slice.byteOffset - buffer.byteOffset);\n}\n"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { TaskSnapshot } from "./types.ts";
|
|
2
|
+
/**
|
|
3
|
+
* none: running, or answered inline by its tool call; pending: a settled handoff
|
|
4
|
+
* awaiting automatic delivery; claimed: handed to the host; delivered: acknowledged.
|
|
5
|
+
*/
|
|
6
|
+
export type TaskDeliveryState = "none" | "pending" | "claimed" | "delivered";
|
|
7
|
+
/**
|
|
8
|
+
* The runtime's state for one task: its working snapshot, retention counters and delivery
|
|
9
|
+
* state. The working snapshot changes only through `update()`, which also drops the frozen
|
|
10
|
+
* copy that readers share, so a mutation can never leave a stale snapshot behind.
|
|
11
|
+
*/
|
|
12
|
+
export declare class TaskRecord {
|
|
13
|
+
/** Read-only view of the working copy; change it with update(). */
|
|
14
|
+
readonly task: Readonly<TaskSnapshot>;
|
|
15
|
+
settled: boolean;
|
|
16
|
+
/** Whether the launch anchor is on the selected branch. */
|
|
17
|
+
visible: boolean;
|
|
18
|
+
pins: number;
|
|
19
|
+
deliveryHolds: number;
|
|
20
|
+
cleanup?: () => void | Promise<void>;
|
|
21
|
+
readError?: string;
|
|
22
|
+
readonly waiters: Set<() => void>;
|
|
23
|
+
private readonly working;
|
|
24
|
+
private frozen?;
|
|
25
|
+
private state;
|
|
26
|
+
constructor(task: TaskSnapshot);
|
|
27
|
+
/** A terminal record rebuilt from persisted history: nothing is left to run or deliver. */
|
|
28
|
+
static restored(task: TaskSnapshot, readError: string | undefined): TaskRecord;
|
|
29
|
+
update(mutate: (task: TaskSnapshot) => void): void;
|
|
30
|
+
/** Readers share one frozen copy, so polling and status rendering never clone unchanged output. */
|
|
31
|
+
snapshot(): TaskSnapshot;
|
|
32
|
+
get delivery(): TaskDeliveryState;
|
|
33
|
+
/** A settled handoff the host has not yet been told about. */
|
|
34
|
+
queueDelivery(): void;
|
|
35
|
+
/** The result was answered inline, or the host acknowledged its delivery. */
|
|
36
|
+
acknowledge(): void;
|
|
37
|
+
/** Only explicit result-delivery holds and active waits delay an automatic completion. */
|
|
38
|
+
get deliverable(): boolean;
|
|
39
|
+
claim(): boolean;
|
|
40
|
+
/** Return a claimed record to pending after a failed delivery. */
|
|
41
|
+
unclaim(): boolean;
|
|
42
|
+
/** Delivered, unpinned and unwatched: bounded history that retention may evict. */
|
|
43
|
+
get inHistory(): boolean;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/record.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAU7E;;;;GAIG;AACH,qBAAa,UAAU;IACtB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACtC,OAAO,UAAS;IAChB,2DAA2D;IAC3D,OAAO,UAAQ;IACf,IAAI,SAAK;IACT,aAAa,SAAK;IAClB,OAAO,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,OAAO,YAAiB,IAAI,EAAI;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,MAAM,CAAC,CAAe;IAC9B,OAAO,CAAC,KAAK,CAA6B;gBAE9B,IAAI,EAAE,YAAY;IAK9B,2FAA2F;IAC3F,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU;IAQ9E,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAQlD,mGAAmG;IACnG,QAAQ,IAAI,YAAY;IAKxB,IAAI,QAAQ,IAAI,iBAAiB,CAEhC;IAED,8DAA8D;IAC9D,aAAa,IAAI,IAAI;IAIrB,6EAA6E;IAC7E,WAAW,IAAI,IAAI;IAInB,0FAA0F;IAC1F,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,KAAK,IAAI,OAAO;IAMhB,kEAAkE;IAClE,OAAO,IAAI,OAAO;IAMlB,mFAAmF;IACnF,IAAI,SAAS,IAAI,OAAO,CAEvB;CACD"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
function freeze(value) {
|
|
2
|
+
if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
|
|
3
|
+
for (const child of Object.values(value))
|
|
4
|
+
freeze(child);
|
|
5
|
+
Object.freeze(value);
|
|
6
|
+
}
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The runtime's state for one task: its working snapshot, retention counters and delivery
|
|
11
|
+
* state. The working snapshot changes only through `update()`, which also drops the frozen
|
|
12
|
+
* copy that readers share, so a mutation can never leave a stale snapshot behind.
|
|
13
|
+
*/
|
|
14
|
+
export class TaskRecord {
|
|
15
|
+
constructor(task) {
|
|
16
|
+
this.settled = false;
|
|
17
|
+
/** Whether the launch anchor is on the selected branch. */
|
|
18
|
+
this.visible = true;
|
|
19
|
+
this.pins = 0;
|
|
20
|
+
this.deliveryHolds = 0;
|
|
21
|
+
this.waiters = new Set();
|
|
22
|
+
this.state = "none";
|
|
23
|
+
this.working = task;
|
|
24
|
+
this.task = task;
|
|
25
|
+
}
|
|
26
|
+
/** A terminal record rebuilt from persisted history: nothing is left to run or deliver. */
|
|
27
|
+
static restored(task, readError) {
|
|
28
|
+
const record = new TaskRecord(task);
|
|
29
|
+
record.settled = true;
|
|
30
|
+
record.state = "delivered";
|
|
31
|
+
record.readError = readError;
|
|
32
|
+
return record;
|
|
33
|
+
}
|
|
34
|
+
update(mutate) {
|
|
35
|
+
try {
|
|
36
|
+
mutate(this.working);
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
this.frozen = undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Readers share one frozen copy, so polling and status rendering never clone unchanged output. */
|
|
43
|
+
snapshot() {
|
|
44
|
+
this.frozen ??= freeze(structuredClone(this.working));
|
|
45
|
+
return this.frozen;
|
|
46
|
+
}
|
|
47
|
+
get delivery() {
|
|
48
|
+
return this.state;
|
|
49
|
+
}
|
|
50
|
+
/** A settled handoff the host has not yet been told about. */
|
|
51
|
+
queueDelivery() {
|
|
52
|
+
this.state = "pending";
|
|
53
|
+
}
|
|
54
|
+
/** The result was answered inline, or the host acknowledged its delivery. */
|
|
55
|
+
acknowledge() {
|
|
56
|
+
this.state = "delivered";
|
|
57
|
+
}
|
|
58
|
+
/** Only explicit result-delivery holds and active waits delay an automatic completion. */
|
|
59
|
+
get deliverable() {
|
|
60
|
+
return this.visible && this.state === "pending" && this.waiters.size === 0 && this.deliveryHolds === 0;
|
|
61
|
+
}
|
|
62
|
+
claim() {
|
|
63
|
+
if (!this.deliverable)
|
|
64
|
+
return false;
|
|
65
|
+
this.state = "claimed";
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
/** Return a claimed record to pending after a failed delivery. */
|
|
69
|
+
unclaim() {
|
|
70
|
+
if (this.state !== "claimed")
|
|
71
|
+
return false;
|
|
72
|
+
this.state = "pending";
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
/** Delivered, unpinned and unwatched: bounded history that retention may evict. */
|
|
76
|
+
get inHistory() {
|
|
77
|
+
return this.settled && this.state === "delivered" && !this.pins && !this.waiters.size;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record.js","sourceRoot":"","sources":["../../../src/core/tasks/record.ts"],"names":[],"mappings":"AAQA,SAAS,MAAM,CAAI,KAAQ;IAC1B,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5E,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC;YAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QACxD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,UAAU;IAetB,YAAY,IAAkB;QAZ9B,YAAO,GAAG,KAAK,CAAC;QAChB,2DAA2D;QAC3D,YAAO,GAAG,IAAI,CAAC;QACf,SAAI,GAAG,CAAC,CAAC;QACT,kBAAa,GAAG,CAAC,CAAC;QAGT,YAAO,GAAG,IAAI,GAAG,EAAc,CAAC;QAGjC,UAAK,GAAsB,MAAM,CAAC;QAGzC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,2FAA2F;IAC3F,MAAM,CAAC,QAAQ,CAAC,IAAkB,EAAE,SAA6B;QAChE,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,MAAM,CAAC,KAAK,GAAG,WAAW,CAAC;QAC3B,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;QAC7B,OAAO,MAAM,CAAC;IACf,CAAC;IAED,MAAM,CAAC,MAAoC;QAC1C,IAAI,CAAC;YACJ,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtB,CAAC;gBAAS,CAAC;YACV,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACzB,CAAC;IACF,CAAC;IAED,mGAAmG;IACnG,QAAQ;QACP,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAED,IAAI,QAAQ;QACX,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IAED,8DAA8D;IAC9D,aAAa;QACZ,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;IACxB,CAAC;IAED,6EAA6E;IAC7E,WAAW;QACV,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC;IAC1B,CAAC;IAED,0FAA0F;IAC1F,IAAI,WAAW;QACd,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,aAAa,KAAK,CAAC,CAAC;IACxG,CAAC;IAED,KAAK;QACJ,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,OAAO,KAAK,CAAC;QACpC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACvB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,kEAAkE;IAClE,OAAO;QACN,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACvB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,mFAAmF;IACnF,IAAI,SAAS;QACZ,OAAO,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,KAAK,WAAW,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IACvF,CAAC;CACD","sourcesContent":["import type { TaskSnapshot } from \"./types.ts\";\n\n/**\n * none: running, or answered inline by its tool call; pending: a settled handoff\n * awaiting automatic delivery; claimed: handed to the host; delivered: acknowledged.\n */\nexport type TaskDeliveryState = \"none\" | \"pending\" | \"claimed\" | \"delivered\";\n\nfunction freeze<T>(value: T): T {\n\tif (value !== null && typeof value === \"object\" && !Object.isFrozen(value)) {\n\t\tfor (const child of Object.values(value)) freeze(child);\n\t\tObject.freeze(value);\n\t}\n\treturn value;\n}\n\n/**\n * The runtime's state for one task: its working snapshot, retention counters and delivery\n * state. The working snapshot changes only through `update()`, which also drops the frozen\n * copy that readers share, so a mutation can never leave a stale snapshot behind.\n */\nexport class TaskRecord {\n\t/** Read-only view of the working copy; change it with update(). */\n\treadonly task: Readonly<TaskSnapshot>;\n\tsettled = false;\n\t/** Whether the launch anchor is on the selected branch. */\n\tvisible = true;\n\tpins = 0;\n\tdeliveryHolds = 0;\n\tcleanup?: () => void | Promise<void>;\n\treadError?: string;\n\treadonly waiters = new Set<() => void>();\n\tprivate readonly working: TaskSnapshot;\n\tprivate frozen?: TaskSnapshot;\n\tprivate state: TaskDeliveryState = \"none\";\n\n\tconstructor(task: TaskSnapshot) {\n\t\tthis.working = task;\n\t\tthis.task = task;\n\t}\n\n\t/** A terminal record rebuilt from persisted history: nothing is left to run or deliver. */\n\tstatic restored(task: TaskSnapshot, readError: string | undefined): TaskRecord {\n\t\tconst record = new TaskRecord(task);\n\t\trecord.settled = true;\n\t\trecord.state = \"delivered\";\n\t\trecord.readError = readError;\n\t\treturn record;\n\t}\n\n\tupdate(mutate: (task: TaskSnapshot) => void): void {\n\t\ttry {\n\t\t\tmutate(this.working);\n\t\t} finally {\n\t\t\tthis.frozen = undefined;\n\t\t}\n\t}\n\n\t/** Readers share one frozen copy, so polling and status rendering never clone unchanged output. */\n\tsnapshot(): TaskSnapshot {\n\t\tthis.frozen ??= freeze(structuredClone(this.working));\n\t\treturn this.frozen;\n\t}\n\n\tget delivery(): TaskDeliveryState {\n\t\treturn this.state;\n\t}\n\n\t/** A settled handoff the host has not yet been told about. */\n\tqueueDelivery(): void {\n\t\tthis.state = \"pending\";\n\t}\n\n\t/** The result was answered inline, or the host acknowledged its delivery. */\n\tacknowledge(): void {\n\t\tthis.state = \"delivered\";\n\t}\n\n\t/** Only explicit result-delivery holds and active waits delay an automatic completion. */\n\tget deliverable(): boolean {\n\t\treturn this.visible && this.state === \"pending\" && this.waiters.size === 0 && this.deliveryHolds === 0;\n\t}\n\n\tclaim(): boolean {\n\t\tif (!this.deliverable) return false;\n\t\tthis.state = \"claimed\";\n\t\treturn true;\n\t}\n\n\t/** Return a claimed record to pending after a failed delivery. */\n\tunclaim(): boolean {\n\t\tif (this.state !== \"claimed\") return false;\n\t\tthis.state = \"pending\";\n\t\treturn true;\n\t}\n\n\t/** Delivered, unpinned and unwatched: bounded history that retention may evict. */\n\tget inHistory(): boolean {\n\t\treturn this.settled && this.state === \"delivered\" && !this.pins && !this.waiters.size;\n\t}\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentToolResult } from "@earendil-works/pi-agent-core";
|
|
2
|
-
import { type TaskExecution, type TaskRead, type TaskRuntimeOptions, type TaskSnapshot, type TasksContext, type TaskToolOutcome } from "./types.ts";
|
|
2
|
+
import { type TaskDeliveryLedger, type TaskExecution, type TaskRead, type TaskReadOptions, type TaskRuntimeOptions, type TaskSnapshot, type TasksContext, type TaskToolOutcome, type TaskWaitAnyOptions, type TaskWaitAnyResult, type TaskWaitOptions, type TaskWaitResult } from "./types.ts";
|
|
3
3
|
/** Session-local supervision. Executors own their processes, items and output files. */
|
|
4
|
-
export declare class TaskRuntime implements TasksContext {
|
|
4
|
+
export declare class TaskRuntime implements TasksContext, TaskDeliveryLedger {
|
|
5
5
|
private readonly store;
|
|
6
6
|
private readonly executions;
|
|
7
7
|
private readonly scheduler;
|
|
@@ -13,7 +13,6 @@ export declare class TaskRuntime implements TasksContext {
|
|
|
13
13
|
private readonly options;
|
|
14
14
|
private configuredEnabled;
|
|
15
15
|
private _closed;
|
|
16
|
-
private pauses;
|
|
17
16
|
constructor(options?: TaskRuntimeOptions);
|
|
18
17
|
get closed(): boolean;
|
|
19
18
|
get session(): TaskRuntimeOptions["session"];
|
|
@@ -28,6 +27,7 @@ export declare class TaskRuntime implements TasksContext {
|
|
|
28
27
|
get enabled(): boolean;
|
|
29
28
|
setEnabled(enabled: boolean): void;
|
|
30
29
|
/** Foreground work is bounded by its caller; only background work, queued or running, holds a slot. */
|
|
30
|
+
private activeBackground;
|
|
31
31
|
private backgroundActive;
|
|
32
32
|
private limitError;
|
|
33
33
|
execute<T>(execution: TaskExecution<T>): Promise<TaskToolOutcome<T>>;
|
|
@@ -38,17 +38,18 @@ export declare class TaskRuntime implements TasksContext {
|
|
|
38
38
|
list(): TaskSnapshot[];
|
|
39
39
|
private lookup;
|
|
40
40
|
get(id: string): TaskSnapshot;
|
|
41
|
-
read(id: string, options?:
|
|
42
|
-
mode?: "head" | "tail";
|
|
43
|
-
bytes?: number;
|
|
44
|
-
sinceBytes?: number;
|
|
45
|
-
}): Promise<TaskRead>;
|
|
41
|
+
read(id: string, options?: TaskReadOptions): Promise<TaskRead>;
|
|
46
42
|
private resultText;
|
|
47
43
|
/** One event-driven waiter can observe a whole waitAny cohort without per-task timers. */
|
|
48
44
|
private waitForRecords;
|
|
49
|
-
/**
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
/**
|
|
46
|
+
* One observation: hold delivery for the observed records, wait, read, then register the
|
|
47
|
+
* receipt with the host, and only then release. Nothing the caller does between those steps
|
|
48
|
+
* can leak a settled result into an automatic notification or lose it.
|
|
49
|
+
*/
|
|
50
|
+
private observe;
|
|
51
|
+
wait(id: string, options?: TaskWaitOptions): Promise<TaskWaitResult>;
|
|
52
|
+
waitAny(options?: TaskWaitAnyOptions): Promise<TaskWaitAnyResult>;
|
|
52
53
|
kill(id: string): boolean;
|
|
53
54
|
private cancel;
|
|
54
55
|
subscribe(listener: () => void): () => void;
|
|
@@ -56,11 +57,10 @@ export declare class TaskRuntime implements TasksContext {
|
|
|
56
57
|
* Retention protects snapshots and logs only. Delivery has its own explicit hold.
|
|
57
58
|
*/
|
|
58
59
|
retain(id: string): () => void;
|
|
60
|
+
private pin;
|
|
59
61
|
holdDelivery(id: string): () => void;
|
|
60
|
-
|
|
62
|
+
private holdRecord;
|
|
61
63
|
pendingNotifications(): TaskSnapshot[];
|
|
62
|
-
/** Only explicit result-delivery holds delay an automatic completion. */
|
|
63
|
-
private candidate;
|
|
64
64
|
claimNotification(id: string): boolean;
|
|
65
65
|
markDelivered(id: string): void;
|
|
66
66
|
releaseNotification(id: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/core/tasks/runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAiBrE,OAAO,EAGN,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAElB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EAEpB,KAAK,cAAc,EACnB,MAAM,YAAY,CAAC;AAEpB,wFAAwF;AACxF,qBAAa,WAAY,YAAW,YAAY,EAAE,kBAAkB;IACnE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAyC;IACpE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuB;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IACnD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,GAAE,kBAAuB;IAwB5C,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,OAAO,IAAI,kBAAkB,CAAC,SAAS,CAAC,CAE3C;IAED;;;;;;OAMG;IACH,cAAc,CACb,OAAO,EAAE,SAAS,OAAO,EAAE,EAC3B,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,GACpE,IAAI;IAIP,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKlC,uGAAuG;IACvG,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,UAAU;IAMZ,OAAO,CAAC,CAAC,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IA6C1E,OAAO,CAAC,UAAU;IAIlB,gBAAgB,IAAI,MAAM;IAe1B,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAK9B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAW3B,IAAI,IAAI,YAAY,EAAE;IAItB,OAAO,CAAC,MAAM;IAad,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY;IAIvB,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAsBxE,OAAO,CAAC,UAAU;IAIlB,0FAA0F;IAC1F,OAAO,CAAC,cAAc;IAkCtB;;;;OAIG;YACW,OAAO;IA8Cf,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IAOxE,OAAO,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAc3E,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAIzB,OAAO,CAAC,MAAM;IAId,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAQ3C;;OAEG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,IAAI;IAI9B,OAAO,CAAC,GAAG;IAaX,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,IAAI;IAIpC,OAAO,CAAC,UAAU;IAYlB,oBAAoB,IAAI,YAAY,EAAE;IAKtC,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAItC,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAO/B,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAMrC,KAAK,IAAI,IAAI;IAYP,QAAQ,CAAC,OAAO,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7C,mFAAmF;IACnF,mBAAmB,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,YAAY,EAAE;IAOnE;;;OAGG;IACG,mBAAmB,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAW1D,KAAK;IAgBnB,OAAO,CAAC,IAAI;CAWZ"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { finiteLimit } from "../../utils/number.js";
|
|
3
|
+
import { Execution } from "./execution.js";
|
|
4
|
+
import { boundWaitMs, TASKS_WAIT_DEFAULT_MS } from "./limits.js";
|
|
5
|
+
import { boundFacts, boundInput, boundText, errorText, readOutputSlice, sliceText, TASK_LABEL_BYTES, TASK_TITLE_BYTES, } from "./output.js";
|
|
6
|
+
import { TaskRecord } from "./record.js";
|
|
5
7
|
import { TaskScheduler } from "./scheduler.js";
|
|
6
|
-
import {
|
|
8
|
+
import { TaskStore } from "./store.js";
|
|
7
9
|
import { TASK_BACKGROUND_REJECTION, TASK_KIND_PATTERN, TaskLookupError, } from "./types.js";
|
|
8
10
|
/** Session-local supervision. Executors own their processes, items and output files. */
|
|
9
11
|
export class TaskRuntime {
|
|
@@ -12,7 +14,6 @@ export class TaskRuntime {
|
|
|
12
14
|
this.scheduler = new TaskScheduler();
|
|
13
15
|
this.listeners = new Set();
|
|
14
16
|
this._closed = false;
|
|
15
|
-
this.pauses = 0;
|
|
16
17
|
this.options = options;
|
|
17
18
|
this.configuredEnabled = options.enabled ?? false;
|
|
18
19
|
this.maxBackground = Math.max(1, finiteLimit(options.maxBackground, 8, 128));
|
|
@@ -59,12 +60,11 @@ export class TaskRuntime {
|
|
|
59
60
|
this.emit();
|
|
60
61
|
}
|
|
61
62
|
/** Foreground work is bounded by its caller; only background work, queued or running, holds a slot. */
|
|
63
|
+
activeBackground() {
|
|
64
|
+
return this.store.unsettled().filter((record) => record.task.mode === "background");
|
|
65
|
+
}
|
|
62
66
|
backgroundActive() {
|
|
63
|
-
|
|
64
|
-
for (const record of this.store.records.values())
|
|
65
|
-
if (!record.settled && record.task.mode === "background")
|
|
66
|
-
count++;
|
|
67
|
-
return count;
|
|
67
|
+
return this.activeBackground().length;
|
|
68
68
|
}
|
|
69
69
|
limitError() {
|
|
70
70
|
return new Error(`Background task limit reached (${this.maxBackground}); stop or wait for a background task, or run in the foreground.`);
|
|
@@ -80,7 +80,7 @@ export class TaskRuntime {
|
|
|
80
80
|
throw new Error("Background execution is not available in this host");
|
|
81
81
|
if (this.backgroundActive() >= this.maxBackground)
|
|
82
82
|
throw this.limitError();
|
|
83
|
-
if (this.store.
|
|
83
|
+
if (this.store.retainedCount() >= this.maxRetained) {
|
|
84
84
|
throw new Error("Task history retention limit reached; deliver pending notifications or release pinned or claimed records");
|
|
85
85
|
}
|
|
86
86
|
}
|
|
@@ -108,17 +108,9 @@ export class TaskRuntime {
|
|
|
108
108
|
status: "queued",
|
|
109
109
|
startedAt: Date.now(),
|
|
110
110
|
};
|
|
111
|
-
const record =
|
|
112
|
-
task,
|
|
113
|
-
settled: false,
|
|
114
|
-
visible: true,
|
|
115
|
-
delivery: "none",
|
|
116
|
-
pins: 0,
|
|
117
|
-
deliveryHolds: 0,
|
|
118
|
-
waiters: new Set(),
|
|
119
|
-
};
|
|
111
|
+
const record = new TaskRecord(task);
|
|
120
112
|
const active = new Execution(this.host, record, execution);
|
|
121
|
-
this.store.
|
|
113
|
+
this.store.add(record);
|
|
122
114
|
this.executions.set(task.id, active);
|
|
123
115
|
this.scheduler.schedule(active);
|
|
124
116
|
// Queued background work returns at once; started work hands off after its own accept().
|
|
@@ -133,15 +125,15 @@ export class TaskRuntime {
|
|
|
133
125
|
detachForeground() {
|
|
134
126
|
if (!this.enabled)
|
|
135
127
|
return 0;
|
|
136
|
-
const eligible = [...this.
|
|
137
|
-
.filter((
|
|
128
|
+
const eligible = [...this.executions.values()]
|
|
129
|
+
.filter((execution) => execution.detachable)
|
|
138
130
|
.sort((left, right) => left.task.startedAt - right.task.startedAt);
|
|
139
131
|
if (!eligible.length)
|
|
140
132
|
return 0;
|
|
141
133
|
const free = this.maxBackground - this.backgroundActive();
|
|
142
134
|
if (free <= 0)
|
|
143
135
|
throw this.limitError();
|
|
144
|
-
const executions = eligible.slice(0, free)
|
|
136
|
+
const executions = eligible.slice(0, free);
|
|
145
137
|
for (const execution of executions)
|
|
146
138
|
execution.requestDetach();
|
|
147
139
|
for (const execution of executions)
|
|
@@ -166,26 +158,26 @@ export class TaskRuntime {
|
|
|
166
158
|
return true;
|
|
167
159
|
}
|
|
168
160
|
list() {
|
|
169
|
-
return
|
|
161
|
+
return this.store.visible().map((record) => record.snapshot());
|
|
170
162
|
}
|
|
171
163
|
lookup(id) {
|
|
172
|
-
const exact = this.store.
|
|
164
|
+
const exact = this.store.get(id);
|
|
173
165
|
if (exact)
|
|
174
166
|
return exact;
|
|
175
|
-
const matches =
|
|
167
|
+
const matches = this.store.match(id);
|
|
176
168
|
if (!id || matches.length !== 1) {
|
|
177
|
-
throw new TaskLookupError(matches.length > 1 ? "ambiguous" : "unknown", matches.map(
|
|
169
|
+
throw new TaskLookupError(matches.length > 1 ? "ambiguous" : "unknown", matches.map((record) => record.snapshot()));
|
|
178
170
|
}
|
|
179
171
|
return matches[0];
|
|
180
172
|
}
|
|
181
173
|
get(id) {
|
|
182
|
-
return
|
|
174
|
+
return this.lookup(id).snapshot();
|
|
183
175
|
}
|
|
184
176
|
async read(id, options = {}) {
|
|
185
177
|
const record = this.lookup(id);
|
|
186
178
|
const release = this.retain(record.task.id);
|
|
187
179
|
try {
|
|
188
|
-
const task =
|
|
180
|
+
const task = record.snapshot();
|
|
189
181
|
if (task.outputPath) {
|
|
190
182
|
try {
|
|
191
183
|
return { task, ...(await readOutputSlice(task.outputPath, options)) };
|
|
@@ -238,34 +230,76 @@ export class TaskRuntime {
|
|
|
238
230
|
record.waiters.add(wake);
|
|
239
231
|
signal?.addEventListener("abort", abort, { once: true });
|
|
240
232
|
interruptSignal?.addEventListener("abort", interrupt, { once: true });
|
|
241
|
-
timer = setTimeout(wake,
|
|
233
|
+
timer = setTimeout(wake, boundWaitMs(timeoutMs));
|
|
242
234
|
if (this.closed || interruptSignal?.aborted)
|
|
243
235
|
wake();
|
|
244
236
|
if (signal?.aborted)
|
|
245
237
|
abort();
|
|
246
238
|
});
|
|
247
239
|
}
|
|
248
|
-
/**
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
240
|
+
/**
|
|
241
|
+
* One observation: hold delivery for the observed records, wait, read, then register the
|
|
242
|
+
* receipt with the host, and only then release. Nothing the caller does between those steps
|
|
243
|
+
* can leak a settled result into an automatic notification or lose it.
|
|
244
|
+
*/
|
|
245
|
+
async observe(records, options,
|
|
246
|
+
/** Record to read when none settled; a cohort has none. */
|
|
247
|
+
fallback) {
|
|
248
|
+
const { signal } = options;
|
|
249
|
+
const releases = records.map((record) => this.holdRecord(record));
|
|
250
|
+
try {
|
|
251
|
+
const start = Date.now();
|
|
252
|
+
const interrupt = this.options.waits?.interruptSignal;
|
|
253
|
+
await this.waitForRecords(records, options.timeoutMs ?? TASKS_WAIT_DEFAULT_MS, signal, interrupt);
|
|
254
|
+
const waitedMs = Date.now() - start;
|
|
255
|
+
const settled = records
|
|
256
|
+
.filter((record) => record.settled)
|
|
257
|
+
.sort((left, right) => (left.task.endedAt ?? 0) - (right.task.endedAt ?? 0))[0];
|
|
258
|
+
const outcome = settled
|
|
259
|
+
? "settled"
|
|
260
|
+
: this.closed
|
|
261
|
+
? "closed"
|
|
262
|
+
: interrupt?.aborted
|
|
263
|
+
? "interrupted"
|
|
264
|
+
: "timed_out";
|
|
265
|
+
const running = records
|
|
266
|
+
.filter((record) => record.visible && !record.settled)
|
|
267
|
+
.map((record) => record.snapshot());
|
|
268
|
+
const observed = settled ?? fallback;
|
|
269
|
+
const read = options.read && observed && outcome !== "interrupted"
|
|
270
|
+
? await this.read(observed.task.id, options.read)
|
|
271
|
+
: undefined;
|
|
272
|
+
signal?.throwIfAborted();
|
|
273
|
+
if (settled && settled.task.mode === "background" && options.toolCallId)
|
|
274
|
+
this.options.waits?.bind(options.toolCallId, settled.task.id);
|
|
275
|
+
return { outcome, waitedMs, settled, running, read };
|
|
276
|
+
}
|
|
277
|
+
finally {
|
|
278
|
+
for (const release of releases)
|
|
279
|
+
release();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
async wait(id, options = {}) {
|
|
283
|
+
if (options.signal?.aborted)
|
|
284
|
+
throw options.signal.reason ?? new Error("Wait aborted");
|
|
252
285
|
const record = this.lookup(id);
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
286
|
+
const { outcome, waitedMs, read } = await this.observe([record], options, record);
|
|
287
|
+
return { outcome, waitedMs, task: record.snapshot(), ...(read ? { read } : {}) };
|
|
288
|
+
}
|
|
289
|
+
async waitAny(options = {}) {
|
|
290
|
+
if (options.signal?.aborted)
|
|
291
|
+
throw options.signal.reason ?? new Error("Wait aborted");
|
|
292
|
+
const records = this.activeBackground().filter((record) => record.visible);
|
|
293
|
+
if (records.length === 0)
|
|
294
|
+
return { outcome: "no_tasks", waitedMs: 0, running: [] };
|
|
295
|
+
const { outcome, waitedMs, settled, running, read } = await this.observe(records, options);
|
|
296
|
+
return {
|
|
297
|
+
outcome,
|
|
298
|
+
waitedMs,
|
|
299
|
+
running,
|
|
300
|
+
...(settled ? { task: settled.snapshot() } : {}),
|
|
301
|
+
...(read ? { read } : {}),
|
|
302
|
+
};
|
|
269
303
|
}
|
|
270
304
|
kill(id) {
|
|
271
305
|
return this.cancel(this.lookup(id));
|
|
@@ -285,7 +319,9 @@ export class TaskRuntime {
|
|
|
285
319
|
* Retention protects snapshots and logs only. Delivery has its own explicit hold.
|
|
286
320
|
*/
|
|
287
321
|
retain(id) {
|
|
288
|
-
|
|
322
|
+
return this.pin(this.lookup(id));
|
|
323
|
+
}
|
|
324
|
+
pin(record) {
|
|
289
325
|
record.pins++;
|
|
290
326
|
let released = false;
|
|
291
327
|
return () => {
|
|
@@ -294,13 +330,16 @@ export class TaskRuntime {
|
|
|
294
330
|
released = true;
|
|
295
331
|
record.pins--;
|
|
296
332
|
this.store.trim();
|
|
297
|
-
|
|
333
|
+
// Listeners decide whether delivery may proceed; TaskDelivery owns pausing.
|
|
334
|
+
if (!this.closed && record.deliverable)
|
|
298
335
|
this.emit();
|
|
299
336
|
};
|
|
300
337
|
}
|
|
301
338
|
holdDelivery(id) {
|
|
302
|
-
|
|
303
|
-
|
|
339
|
+
return this.holdRecord(this.lookup(id));
|
|
340
|
+
}
|
|
341
|
+
holdRecord(record) {
|
|
342
|
+
const releasePin = this.pin(record);
|
|
304
343
|
record.deliveryHolds++;
|
|
305
344
|
let released = false;
|
|
306
345
|
return () => {
|
|
@@ -308,50 +347,27 @@ export class TaskRuntime {
|
|
|
308
347
|
return;
|
|
309
348
|
released = true;
|
|
310
349
|
record.deliveryHolds--;
|
|
311
|
-
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
pause() {
|
|
315
|
-
this.pauses++;
|
|
316
|
-
let resumed = false;
|
|
317
|
-
return () => {
|
|
318
|
-
if (resumed)
|
|
319
|
-
return;
|
|
320
|
-
resumed = true;
|
|
321
|
-
this.pauses--;
|
|
322
|
-
this.emit();
|
|
350
|
+
releasePin();
|
|
323
351
|
};
|
|
324
352
|
}
|
|
325
353
|
pendingNotifications() {
|
|
326
|
-
if (this.closed
|
|
354
|
+
if (this.closed)
|
|
327
355
|
return [];
|
|
328
|
-
return
|
|
329
|
-
}
|
|
330
|
-
/** Only explicit result-delivery holds delay an automatic completion. */
|
|
331
|
-
candidate(record) {
|
|
332
|
-
return record.visible && record.delivery === "pending" && record.waiters.size === 0 && record.deliveryHolds === 0;
|
|
356
|
+
return this.store.deliverable().map((record) => record.snapshot());
|
|
333
357
|
}
|
|
334
358
|
claimNotification(id) {
|
|
335
|
-
|
|
336
|
-
return false;
|
|
337
|
-
const record = this.store.records.get(id);
|
|
338
|
-
if (!record || !this.candidate(record))
|
|
339
|
-
return false;
|
|
340
|
-
record.delivery = "claimed";
|
|
341
|
-
return true;
|
|
359
|
+
return !this.closed && (this.store.get(id)?.claim() ?? false);
|
|
342
360
|
}
|
|
343
361
|
markDelivered(id) {
|
|
344
|
-
const record = this.store.
|
|
362
|
+
const record = this.store.get(id);
|
|
345
363
|
if (!record)
|
|
346
364
|
return;
|
|
347
|
-
record.
|
|
365
|
+
record.acknowledge();
|
|
348
366
|
this.store.trim();
|
|
349
367
|
}
|
|
350
368
|
releaseNotification(id) {
|
|
351
|
-
|
|
352
|
-
if (!record || record.delivery !== "claimed")
|
|
369
|
+
if (!this.store.get(id)?.unclaim())
|
|
353
370
|
return;
|
|
354
|
-
record.delivery = "pending";
|
|
355
371
|
this.store.trim();
|
|
356
372
|
this.emit();
|
|
357
373
|
}
|
|
@@ -360,7 +376,7 @@ export class TaskRuntime {
|
|
|
360
376
|
return;
|
|
361
377
|
this._closed = true;
|
|
362
378
|
this.listeners.clear();
|
|
363
|
-
for (const record of this.store.
|
|
379
|
+
for (const record of this.store.all()) {
|
|
364
380
|
this.executions.get(record.task.id)?.releaseParent();
|
|
365
381
|
this.cancel(record);
|
|
366
382
|
for (const waiter of [...record.waiters])
|
|
@@ -370,22 +386,24 @@ export class TaskRuntime {
|
|
|
370
386
|
}
|
|
371
387
|
async shutdown(graceMs = 2000) {
|
|
372
388
|
this.close();
|
|
373
|
-
await this.drain(
|
|
389
|
+
await this.drain(this.store.all(), graceMs);
|
|
374
390
|
}
|
|
375
391
|
/** Running tasks whose launch anchor is outside the branch made of `ancestors`. */
|
|
376
392
|
activeOutsideBranch(ancestors) {
|
|
377
|
-
return
|
|
378
|
-
.
|
|
379
|
-
.
|
|
393
|
+
return this.store
|
|
394
|
+
.unsettled()
|
|
395
|
+
.filter((record) => record.task.anchorId !== null && !ancestors.has(record.task.anchorId))
|
|
396
|
+
.map((record) => record.snapshot());
|
|
380
397
|
}
|
|
381
398
|
/**
|
|
382
399
|
* Hidden results stay pending: returning to their branch delivers them again.
|
|
383
400
|
* Restored history is already delivered.
|
|
384
401
|
*/
|
|
385
402
|
async cancelOutsideBranch(ancestors) {
|
|
386
|
-
|
|
403
|
+
const records = this.store.all();
|
|
404
|
+
for (const record of records)
|
|
387
405
|
record.visible = record.task.anchorId === null || ancestors.has(record.task.anchorId);
|
|
388
|
-
const outside =
|
|
406
|
+
const outside = records.filter((record) => !record.visible);
|
|
389
407
|
for (const record of outside)
|
|
390
408
|
this.cancel(record);
|
|
391
409
|
this.store.trim();
|
|
@@ -396,7 +414,7 @@ export class TaskRuntime {
|
|
|
396
414
|
let timer;
|
|
397
415
|
try {
|
|
398
416
|
await Promise.race([
|
|
399
|
-
Promise.all(records.map((record) => this.executions.get(record.task.id)?.done)).then(() =>
|
|
417
|
+
Promise.all(records.map((record) => this.executions.get(record.task.id)?.done)).then(() => this.store.cleanupsDone()),
|
|
400
418
|
new Promise((resolve) => {
|
|
401
419
|
timer = setTimeout(resolve, finiteLimit(graceMs, 2000, 60_000));
|
|
402
420
|
}),
|