@noetic-tools/core 0.0.1 → 0.1.1
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/README.md +31 -11
- package/dist/adapters/in-memory-fs-adapter.d.ts +1 -1
- package/dist/adapters/in-memory-fs-adapter.js +1 -1
- package/dist/adapters/in-memory-shell-adapter.d.ts +1 -1
- package/dist/adapters/in-memory-subprocess/manifest-persistence.d.ts +8 -0
- package/dist/adapters/in-memory-subprocess/manifest-persistence.js +56 -0
- package/dist/adapters/in-memory-subprocess/metadata.d.ts +12 -0
- package/dist/adapters/in-memory-subprocess/metadata.js +58 -0
- package/dist/adapters/in-memory-subprocess/step-completion.d.ts +3 -0
- package/dist/adapters/in-memory-subprocess/step-completion.js +86 -0
- package/dist/adapters/in-memory-subprocess/types.d.ts +88 -0
- package/dist/adapters/in-memory-subprocess/types.js +2 -0
- package/dist/adapters/in-memory-subprocess-adapter.d.ts +12 -4
- package/dist/adapters/in-memory-subprocess-adapter.js +164 -55
- package/dist/adapters/openrouter.d.ts +16 -7
- package/dist/adapters/openrouter.js +68 -7
- package/dist/builders/channel-builder.d.ts +1 -1
- package/dist/builders/control-flow-builders.d.ts +3 -3
- package/dist/builders/control-flow-builders.js +9 -4
- package/dist/builders/every.d.ts +3 -3
- package/dist/builders/every.js +5 -2
- package/dist/builders/layer-provides-builders.d.ts +1 -32
- package/dist/builders/layer-provides-builders.js +1 -33
- package/dist/builders/loop-builder.d.ts +2 -2
- package/dist/builders/loop-builder.js +5 -2
- package/dist/builders/memory-builder.d.ts +1 -1
- package/dist/builders/memory-builder.js +1 -1
- package/dist/builders/provide-builder.d.ts +2 -2
- package/dist/builders/provide-builder.js +5 -2
- package/dist/builders/spawn-builder.d.ts +22 -9
- package/dist/builders/spawn-builder.js +17 -3
- package/dist/builders/step-builders.d.ts +51 -30
- package/dist/builders/step-builders.js +31 -12
- package/dist/builders/tool-builder.d.ts +7 -3
- package/dist/builders/tool-builder.js +3 -1
- package/dist/builders/workflow-hydrator.d.ts +38 -0
- package/dist/builders/workflow-hydrator.js +336 -0
- package/dist/conditions/conditions.d.ts +4 -4
- package/dist/conditions/conditions.js +2 -2
- package/dist/errors/noetic-error.d.ts +1 -1
- package/dist/errors/noetic-error.js +2 -0
- package/dist/{runtime → harness}/agent-harness.d.ts +65 -45
- package/dist/harness/agent-harness.js +576 -0
- package/dist/harness/deps/adapters.d.ts +4 -0
- package/dist/harness/deps/adapters.js +4 -0
- package/dist/harness/deps/interpreter.d.ts +5 -0
- package/dist/harness/deps/interpreter.js +4 -0
- package/dist/harness/deps/memory.d.ts +5 -0
- package/dist/harness/deps/memory.js +4 -0
- package/dist/harness/deps/runtime.d.ts +10 -0
- package/dist/harness/deps/runtime.js +7 -0
- package/dist/harness/deps/types.d.ts +17 -0
- package/dist/harness/deps/types.js +1 -0
- package/dist/harness/model-call.d.ts +50 -0
- package/dist/harness/model-call.js +694 -0
- package/dist/harness/model-schema.d.ts +19 -0
- package/dist/harness/model-schema.js +46 -0
- package/dist/harness/step-bootstrap.d.ts +25 -0
- package/dist/harness/step-bootstrap.js +170 -0
- package/dist/index.d.ts +114 -76
- package/dist/index.js +74 -50
- package/dist/internal-test.d.ts +4 -4
- package/dist/internal-test.js +4 -4
- package/dist/interpreter/action-deps.d.ts +12 -0
- package/dist/interpreter/action-deps.js +10 -0
- package/dist/interpreter/action-types.d.ts +8 -0
- package/dist/interpreter/action-types.js +1 -0
- package/dist/interpreter/collect-tools.d.ts +2 -2
- package/dist/interpreter/collect-tools.js +6 -2
- package/dist/interpreter/execute-action.d.ts +22 -0
- package/dist/interpreter/execute-action.js +527 -0
- package/dist/interpreter/{execute-every.d.ts → execute-control.d.ts} +8 -2
- package/dist/interpreter/execute-control.js +530 -0
- package/dist/interpreter/execute.d.ts +16 -3
- package/dist/interpreter/execute.js +154 -51
- package/dist/interpreter/message-helpers.d.ts +1 -9
- package/dist/interpreter/message-helpers.js +1 -42
- package/dist/interpreter/step-dispatcher.d.ts +61 -0
- package/dist/interpreter/step-dispatcher.js +67 -0
- package/dist/interpreter/typeguards.d.ts +8 -15
- package/dist/interpreter/typeguards.js +4 -21
- package/dist/memory/budget.d.ts +2 -2
- package/dist/memory/budget.js +1 -1
- package/dist/{runtime → memory}/exec-context-factory.d.ts +2 -2
- package/dist/{runtime → memory}/exec-context-factory.js +1 -1
- package/dist/memory/flow-schema.d.ts +52 -0
- package/dist/memory/flow-schema.js +102 -0
- package/dist/memory/function-call-utils.d.ts +1 -1
- package/dist/memory/function-call-utils.js +4 -2
- package/dist/memory/layer-api.d.ts +4 -4
- package/dist/memory/layer-api.js +2 -2
- package/dist/memory/layer-lifecycle.d.ts +6 -6
- package/dist/memory/layer-lifecycle.js +6 -6
- package/dist/memory/layer-provides.d.ts +32 -0
- package/dist/memory/layer-provides.js +33 -0
- package/dist/memory/layer-usage.d.ts +4 -3
- package/dist/memory/layer-usage.js +9 -3
- package/dist/memory/layers/durable-task-state.d.ts +8 -8
- package/dist/memory/layers/durable-task-state.js +2 -2
- package/dist/memory/layers/file-reference.d.ts +1 -1
- package/dist/memory/layers/file-reference.js +303 -247
- package/dist/memory/layers/history-window.d.ts +1 -1
- package/dist/memory/layers/history-window.js +4 -4
- package/dist/memory/layers/observational-memory.d.ts +5 -5
- package/dist/memory/layers/observational-memory.js +2 -3
- package/dist/memory/layers/plan.d.ts +2 -2
- package/dist/memory/layers/plan.js +15 -10
- package/dist/memory/layers/static-content.d.ts +2 -2
- package/dist/memory/layers/static-content.js +1 -1
- package/dist/memory/layers/steering.d.ts +7 -7
- package/dist/memory/layers/steering.js +5 -5
- package/dist/memory/layers/tool-memory-layer.d.ts +2 -2
- package/dist/memory/layers/tool-memory-layer.js +1 -1
- package/dist/memory/layers/working-memory.d.ts +7 -7
- package/dist/memory/layers/working-memory.js +4 -4
- package/dist/memory/projector.d.ts +2 -2
- package/dist/memory/scope.d.ts +1 -1
- package/dist/memory/strip-unresolved.d.ts +1 -1
- package/dist/observability/span-impl.d.ts +1 -1
- package/dist/observability/trace-exporter.d.ts +2 -2
- package/dist/observability/trace-exporter.js +1 -1
- package/dist/patterns/dynamic-workflow.d.ts +55 -0
- package/dist/patterns/dynamic-workflow.js +194 -0
- package/dist/patterns/flow.d.ts +2 -52
- package/dist/patterns/flow.js +1 -103
- package/dist/patterns/interview.d.ts +2 -2
- package/dist/patterns/interview.js +5 -5
- package/dist/patterns/plans.d.ts +6 -6
- package/dist/patterns/plans.js +4 -4
- package/dist/patterns/ralph-wiggum.d.ts +4 -4
- package/dist/patterns/ralph-wiggum.js +5 -5
- package/dist/patterns/react.d.ts +3 -3
- package/dist/patterns/react.js +5 -5
- package/dist/portable/adapters.d.ts +6 -0
- package/dist/portable/adapters.js +6 -0
- package/dist/portable/ask-user.d.ts +4 -0
- package/dist/portable/ask-user.js +2 -0
- package/dist/portable/builders.d.ts +12 -0
- package/dist/portable/builders.js +12 -0
- package/dist/portable/memory-layers.d.ts +12 -0
- package/dist/portable/memory-layers.js +12 -0
- package/dist/portable/runtime.d.ts +4 -0
- package/dist/portable/runtime.js +4 -0
- package/dist/portable/until.d.ts +4 -0
- package/dist/portable/until.js +4 -0
- package/dist/portable.d.ts +8 -26
- package/dist/portable.js +8 -34
- package/dist/runtime/broadcaster-utils.d.ts +7 -3
- package/dist/runtime/broadcaster-utils.js +11 -6
- package/dist/runtime/channel-store.d.ts +1 -1
- package/dist/runtime/channel-store.js +2 -2
- package/dist/runtime/context-deps.d.ts +4 -0
- package/dist/runtime/context-deps.js +2 -0
- package/dist/runtime/context-impl.d.ts +42 -12
- package/dist/runtime/context-impl.js +52 -5
- package/dist/runtime/context-type-deps.d.ts +14 -0
- package/dist/runtime/context-type-deps.js +1 -0
- package/dist/runtime/cwd-helpers.d.ts +1 -1
- package/dist/runtime/detached-handle.d.ts +52 -4
- package/dist/runtime/detached-handle.js +218 -14
- package/dist/runtime/durable/checkpoint-store.d.ts +38 -0
- package/dist/runtime/durable/checkpoint-store.js +101 -0
- package/dist/runtime/durable/detached-signal.d.ts +37 -0
- package/dist/runtime/durable/detached-signal.js +52 -0
- package/dist/runtime/durable/harness-checkpoints.d.ts +51 -0
- package/dist/runtime/durable/harness-checkpoints.js +104 -0
- package/dist/runtime/durable/index.d.ts +10 -0
- package/dist/runtime/durable/index.js +5 -0
- package/dist/runtime/durable/runnable-loop.d.ts +100 -0
- package/dist/runtime/durable/runnable-loop.js +90 -0
- package/dist/runtime/durable/session-seed.d.ts +28 -0
- package/dist/runtime/durable/session-seed.js +27 -0
- package/dist/runtime/durable/stall-nudge.d.ts +82 -0
- package/dist/runtime/durable/stall-nudge.js +87 -0
- package/dist/runtime/event-broadcaster.d.ts +1 -1
- package/dist/runtime/in-memory-storage.d.ts +1 -1
- package/dist/runtime/in-memory-storage.js +1 -1
- package/dist/runtime/item-log-impl.d.ts +3 -3
- package/dist/runtime/item-log-impl.js +1 -1
- package/dist/runtime/message-queue.d.ts +2 -2
- package/dist/runtime/session-runner.d.ts +7 -7
- package/dist/runtime/session-runner.js +3 -3
- package/dist/runtime/session-streams.d.ts +3 -3
- package/dist/runtime/session-streams.js +1 -1
- package/dist/runtime/step-registry.d.ts +42 -0
- package/dist/runtime/step-registry.js +77 -0
- package/dist/runtime/tool-memory.d.ts +3 -3
- package/dist/schemas/item.d.ts +1 -1
- package/dist/schemas/workflow.d.ts +139 -0
- package/dist/schemas/workflow.js +232 -0
- package/dist/types/ask-user-types.d.ts +57 -0
- package/dist/types/ask-user-types.js +74 -0
- package/dist/types/checkpoint.d.ts +98 -0
- package/dist/types/checkpoint.js +81 -0
- package/dist/types/common.d.ts +1 -50
- package/dist/types/context-parts/item-log.d.ts +6 -0
- package/dist/types/context-parts/item-log.js +1 -0
- package/dist/types/context-parts/layer-usage.d.ts +18 -0
- package/dist/types/context-parts/layer-usage.js +1 -0
- package/dist/types/context.d.ts +140 -31
- package/dist/types/error.d.ts +15 -0
- package/dist/types/harness-result.d.ts +2 -2
- package/dist/types/items.d.ts +18 -2
- package/dist/types/memory-context.d.ts +39 -0
- package/dist/types/memory-context.js +1 -0
- package/dist/types/memory.d.ts +38 -68
- package/dist/types/mutable-context.d.ts +3 -3
- package/dist/types/runtime.d.ts +14 -13
- package/dist/types/steering.d.ts +2 -2
- package/dist/types/step-registrar.d.ts +46 -0
- package/dist/types/step-registrar.js +56 -0
- package/dist/types/step.d.ts +34 -9
- package/dist/types/subprocess-adapter.d.ts +119 -3
- package/dist/types/subprocess-adapter.js +2 -0
- package/dist/types/tool-context.d.ts +6 -6
- package/dist/types/tool.d.ts +64 -0
- package/dist/types/tool.js +1 -0
- package/dist/unstable.d.ts +9 -9
- package/dist/unstable.js +7 -7
- package/dist/until/combinators.d.ts +1 -1
- package/dist/until/never.d.ts +1 -1
- package/dist/until/predicates.d.ts +13 -4
- package/dist/until/predicates.js +16 -2
- package/dist/util/message-helpers.d.ts +17 -0
- package/dist/util/message-helpers.js +64 -0
- package/package.json +6 -4
- package/dist/adapters/local-fs-adapter.d.ts +0 -3
- package/dist/adapters/local-fs-adapter.js +0 -43
- package/dist/adapters/local-shell-adapter.d.ts +0 -51
- package/dist/adapters/local-shell-adapter.js +0 -167
- package/dist/adapters/local-subprocess-adapter.d.ts +0 -16
- package/dist/adapters/local-subprocess-adapter.js +0 -187
- package/dist/conditions/index.d.ts +0 -3
- package/dist/conditions/index.js +0 -2
- package/dist/interpreter/execute-branch.d.ts +0 -3
- package/dist/interpreter/execute-branch.js +0 -10
- package/dist/interpreter/execute-every.js +0 -143
- package/dist/interpreter/execute-fork.d.ts +0 -3
- package/dist/interpreter/execute-fork.js +0 -215
- package/dist/interpreter/execute-llm.d.ts +0 -4
- package/dist/interpreter/execute-llm.js +0 -217
- package/dist/interpreter/execute-loop.d.ts +0 -3
- package/dist/interpreter/execute-loop.js +0 -171
- package/dist/interpreter/execute-provide.d.ts +0 -10
- package/dist/interpreter/execute-provide.js +0 -64
- package/dist/interpreter/execute-run.d.ts +0 -3
- package/dist/interpreter/execute-run.js +0 -39
- package/dist/interpreter/execute-spawn.d.ts +0 -11
- package/dist/interpreter/execute-spawn.js +0 -113
- package/dist/interpreter/execute-tool.d.ts +0 -5
- package/dist/interpreter/execute-tool.js +0 -81
- package/dist/runtime/agent-harness.js +0 -1170
- /package/dist/{interpreter → util}/framework-cast.d.ts +0 -0
- /package/dist/{interpreter → util}/framework-cast.js +0 -0
package/dist/unstable.js
CHANGED
|
@@ -6,19 +6,19 @@
|
|
|
6
6
|
* They are intended for authors of custom memory layers, runtime backends,
|
|
7
7
|
* and other framework extensions. Do not depend on them in application code.
|
|
8
8
|
*/
|
|
9
|
-
/** @unstable Unsafe cast utility for bridging internal type boundaries. */
|
|
10
|
-
export { frameworkCast } from './interpreter/framework-cast';
|
|
11
9
|
/** @unstable Budget allocation and checking utilities. */
|
|
12
|
-
export { allocateBudgets, checkBudget } from './memory/budget';
|
|
10
|
+
export { allocateBudgets, checkBudget } from './memory/budget.js';
|
|
13
11
|
/** @unstable Factory for creating layer state stores. */
|
|
14
|
-
export { createLayerStateStore } from './memory/layer-lifecycle';
|
|
12
|
+
export { createLayerStateStore } from './memory/layer-lifecycle.js';
|
|
15
13
|
/** @unstable View assembly algorithm that converges memory layer outputs into the LLM context. */
|
|
16
|
-
export { assembleView } from './memory/projector';
|
|
14
|
+
export { assembleView } from './memory/projector.js';
|
|
17
15
|
/** @unstable Factory for creating scoped storage wrappers around a StorageAdapter. */
|
|
18
|
-
export { createScopedStorage } from './memory/scope';
|
|
16
|
+
export { createScopedStorage } from './memory/scope.js';
|
|
19
17
|
/**
|
|
20
18
|
* @unstable Internal helper used by sync agent-spawn paths (worktree isolation)
|
|
21
19
|
* to seed a child's cwd snapshot without touching `previousCwd`. Not part of
|
|
22
20
|
* the public surface — call sites must hold exclusive use of the parent ctx.
|
|
23
21
|
*/
|
|
24
|
-
export { retargetCwdForSpawn } from './runtime/cwd-helpers';
|
|
22
|
+
export { retargetCwdForSpawn } from './runtime/cwd-helpers.js';
|
|
23
|
+
/** @unstable Unsafe cast utility for bridging internal type boundaries. */
|
|
24
|
+
export { frameworkCast } from './util/framework-cast.js';
|
package/dist/until/never.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { EmbedFn } from '../types/embed';
|
|
2
|
-
import type { StorageAdapter } from '../types/memory';
|
|
3
|
-
import type { Until } from '../types/step';
|
|
4
|
-
import { never } from './never';
|
|
1
|
+
import type { EmbedFn } from '../types/embed.js';
|
|
2
|
+
import type { StorageAdapter } from '../types/memory.js';
|
|
3
|
+
import type { Until } from '../types/step.js';
|
|
4
|
+
import { never } from './never.js';
|
|
5
5
|
/** @public Async verification function that checks loop output and optionally returns feedback. */
|
|
6
6
|
export type VerifyFn = (output: unknown) => Promise<{
|
|
7
7
|
pass: boolean;
|
|
@@ -38,6 +38,15 @@ export declare const until: {
|
|
|
38
38
|
converged(opts: ConvergeConfig): Until;
|
|
39
39
|
/** Stops the loop when the last output text contains the given marker string. @public */
|
|
40
40
|
outputContains(marker: string): Until;
|
|
41
|
+
/**
|
|
42
|
+
* Stops the loop when the last output text exactly equals the given
|
|
43
|
+
* sentinel string. Prefer this over `outputContains` when the marker is a
|
|
44
|
+
* dedicated exit sentinel produced by a terminator step — exact equality
|
|
45
|
+
* avoids substring collisions with unrelated step output that happens to
|
|
46
|
+
* quote the sentinel.
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
outputEquals(sentinel: string): Until;
|
|
41
50
|
/** Wraps an arbitrary `Until` function as a named predicate. @public */
|
|
42
51
|
custom(fn: Until): Until;
|
|
43
52
|
};
|
package/dist/until/predicates.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { cosineSimilarity } from '../conditions/cosine-similarity';
|
|
2
|
-
import { never } from './never';
|
|
1
|
+
import { cosineSimilarity } from '../conditions/cosine-similarity.js';
|
|
2
|
+
import { never } from './never.js';
|
|
3
3
|
const CONVERGE_CACHE_KEY = 'converge:previousVector';
|
|
4
4
|
/**
|
|
5
5
|
* Namespace of built-in loop termination predicates.
|
|
@@ -119,6 +119,20 @@ export const until = {
|
|
|
119
119
|
reason: snap.lastText.includes(marker) ? `Output contains marker: ${marker}` : undefined,
|
|
120
120
|
});
|
|
121
121
|
},
|
|
122
|
+
/**
|
|
123
|
+
* Stops the loop when the last output text exactly equals the given
|
|
124
|
+
* sentinel string. Prefer this over `outputContains` when the marker is a
|
|
125
|
+
* dedicated exit sentinel produced by a terminator step — exact equality
|
|
126
|
+
* avoids substring collisions with unrelated step output that happens to
|
|
127
|
+
* quote the sentinel.
|
|
128
|
+
* @public
|
|
129
|
+
*/
|
|
130
|
+
outputEquals(sentinel) {
|
|
131
|
+
return (snap) => ({
|
|
132
|
+
stop: snap.lastText === sentinel,
|
|
133
|
+
reason: snap.lastText === sentinel ? `Output matched sentinel: ${sentinel}` : undefined,
|
|
134
|
+
});
|
|
135
|
+
},
|
|
122
136
|
/** Wraps an arbitrary `Until` function as a named predicate. @public */
|
|
123
137
|
custom(fn) {
|
|
124
138
|
return fn;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { LLMResponse } from '../types/common.js';
|
|
2
|
+
import type { Context } from '../types/context.js';
|
|
3
|
+
import type { InputMessageItem, Item, MessageItem } from '../types/items.js';
|
|
4
|
+
export declare function isAssistantMessage(item: unknown): item is MessageItem;
|
|
5
|
+
export declare function isUserMessage(item: unknown): item is MessageItem;
|
|
6
|
+
export declare function isOutputText(part: {
|
|
7
|
+
type: string;
|
|
8
|
+
}): part is {
|
|
9
|
+
type: 'output_text';
|
|
10
|
+
text: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function createMessage(text: string, role: 'user' | 'developer'): InputMessageItem;
|
|
13
|
+
export declare function extractAssistantText(items: ReadonlyArray<Item>): string;
|
|
14
|
+
/** Naive token estimate: ~4 chars per token */
|
|
15
|
+
export declare function estimateTokens(text: string): number;
|
|
16
|
+
/** Accumulate token usage and cost from an LLM response onto a mutable context. */
|
|
17
|
+
export declare function trackUsage(ctx: Context, response: LLMResponse): void;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
function canTrackUsage(ctx) {
|
|
2
|
+
const desc = Object.getOwnPropertyDescriptor(ctx, 'stepCount');
|
|
3
|
+
return desc !== undefined && desc.writable !== false;
|
|
4
|
+
}
|
|
5
|
+
export function isAssistantMessage(item) {
|
|
6
|
+
return (typeof item === 'object' &&
|
|
7
|
+
item !== null &&
|
|
8
|
+
'type' in item &&
|
|
9
|
+
item.type === 'message' &&
|
|
10
|
+
'role' in item &&
|
|
11
|
+
item.role === 'assistant');
|
|
12
|
+
}
|
|
13
|
+
export function isUserMessage(item) {
|
|
14
|
+
return (typeof item === 'object' &&
|
|
15
|
+
item !== null &&
|
|
16
|
+
'type' in item &&
|
|
17
|
+
item.type === 'message' &&
|
|
18
|
+
'role' in item &&
|
|
19
|
+
item.role === 'user');
|
|
20
|
+
}
|
|
21
|
+
export function isOutputText(part) {
|
|
22
|
+
return part.type === 'output_text';
|
|
23
|
+
}
|
|
24
|
+
export function createMessage(text, role) {
|
|
25
|
+
return {
|
|
26
|
+
id: crypto.randomUUID(),
|
|
27
|
+
status: 'completed',
|
|
28
|
+
type: 'message',
|
|
29
|
+
role,
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: 'input_text',
|
|
33
|
+
text,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function extractAssistantText(items) {
|
|
39
|
+
const lastMsg = items.findLast(isAssistantMessage);
|
|
40
|
+
if (!lastMsg) {
|
|
41
|
+
return '';
|
|
42
|
+
}
|
|
43
|
+
return (lastMsg.content
|
|
44
|
+
?.filter(isOutputText)
|
|
45
|
+
?.map((c) => c.text)
|
|
46
|
+
?.join('') ?? '');
|
|
47
|
+
}
|
|
48
|
+
/** Naive token estimate: ~4 chars per token */
|
|
49
|
+
export function estimateTokens(text) {
|
|
50
|
+
return Math.ceil(text.length / 4);
|
|
51
|
+
}
|
|
52
|
+
/** Accumulate token usage and cost from an LLM response onto a mutable context. */
|
|
53
|
+
export function trackUsage(ctx, response) {
|
|
54
|
+
if (!canTrackUsage(ctx)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
ctx.tokens.input += response.usage.inputTokens;
|
|
58
|
+
ctx.tokens.output += response.usage.outputTokens;
|
|
59
|
+
ctx.tokens.total += response.usage.inputTokens + response.usage.outputTokens;
|
|
60
|
+
ctx.tokens.cached = (ctx.tokens.cached ?? 0) + (response.usage.cachedTokens ?? 0);
|
|
61
|
+
if (response.cost) {
|
|
62
|
+
ctx.cost = ctx.cost + response.cost;
|
|
63
|
+
}
|
|
64
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noetic-tools/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Step primitives, interpreter, runtime, and memory layer contract for Noetic agents.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
"./internal/test": {
|
|
40
40
|
"types": "./dist/internal-test.d.ts",
|
|
41
41
|
"default": "./dist/internal-test.js"
|
|
42
|
-
}
|
|
42
|
+
},
|
|
43
|
+
"./package.json": "./package.json"
|
|
43
44
|
},
|
|
44
45
|
"files": [
|
|
45
46
|
"dist",
|
|
@@ -67,8 +68,9 @@
|
|
|
67
68
|
"zod": "^4.0.0"
|
|
68
69
|
},
|
|
69
70
|
"scripts": {
|
|
70
|
-
"build": "bunx tsc -p tsconfig.build.json",
|
|
71
|
-
"
|
|
71
|
+
"build": "bunx tsc -p tsconfig.build.json && bun scripts/add-js-extensions.ts",
|
|
72
|
+
"verify:esm": "bun scripts/verify-node-esm.ts",
|
|
73
|
+
"prepublishOnly": "rm -rf dist && bun run build && bun run verify:esm",
|
|
72
74
|
"test": "bun test",
|
|
73
75
|
"test:coverage": "bun test --coverage --coverage-reporter=text --coverage-reporter=json",
|
|
74
76
|
"test:ci": "bun test --coverage --coverage-reporter=json",
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
//#region Helpers
|
|
2
|
-
function toFsStats(s) {
|
|
3
|
-
return {
|
|
4
|
-
size: s.size,
|
|
5
|
-
isDirectory: () => s.isDirectory(),
|
|
6
|
-
isSymbolicLink: () => s.isSymbolicLink(),
|
|
7
|
-
isFile: () => s.isFile(),
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
//#endregion
|
|
11
|
-
//#region Public API
|
|
12
|
-
/** Create an FsAdapter backed by the local filesystem via `node:fs/promises`. */
|
|
13
|
-
export function createLocalFsAdapter() {
|
|
14
|
-
const fs = () => import('node:fs/promises');
|
|
15
|
-
const fsConstants = () => import('node:fs');
|
|
16
|
-
return {
|
|
17
|
-
readFile: async (p) => (await fs()).readFile(p),
|
|
18
|
-
readFileText: async (p) => (await fs()).readFile(p, 'utf-8'),
|
|
19
|
-
writeFile: async (p, content) => (await fs()).writeFile(p, content, 'utf-8'),
|
|
20
|
-
writeFileBytes: async (p, content) => (await fs()).writeFile(p, content),
|
|
21
|
-
appendFile: async (p, content) => (await fs()).appendFile(p, content, 'utf-8'),
|
|
22
|
-
mkdir: async (dir) => {
|
|
23
|
-
await (await fs()).mkdir(dir, {
|
|
24
|
-
recursive: true,
|
|
25
|
-
});
|
|
26
|
-
},
|
|
27
|
-
rename: async (oldPath, newPath) => (await fs()).rename(oldPath, newPath),
|
|
28
|
-
rm: async (p, options) => {
|
|
29
|
-
await (await fs()).rm(p, options);
|
|
30
|
-
},
|
|
31
|
-
access: async (p, mode) => {
|
|
32
|
-
const [{ constants }, fsPromises] = await Promise.all([
|
|
33
|
-
fsConstants(),
|
|
34
|
-
fs(),
|
|
35
|
-
]);
|
|
36
|
-
await fsPromises.access(p, mode ?? constants.R_OK);
|
|
37
|
-
},
|
|
38
|
-
stat: async (p) => toFsStats(await (await fs()).stat(p)),
|
|
39
|
-
lstat: async (p) => toFsStats(await (await fs()).lstat(p)),
|
|
40
|
-
readdir: async (p) => (await fs()).readdir(p),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
//#endregion
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { ShellAdapter } from '../types/shell-adapter';
|
|
2
|
-
/**
|
|
3
|
-
* Options for `createLocalShellAdapter`.
|
|
4
|
-
*
|
|
5
|
-
* @public
|
|
6
|
-
*/
|
|
7
|
-
export interface CreateLocalShellAdapterOptions {
|
|
8
|
-
/**
|
|
9
|
-
* When `true`, every command is rewritten through `rtk rewrite`
|
|
10
|
-
* (https://github.com/rtk-ai/rtk) before exec to filter and summarize
|
|
11
|
-
* output for token efficiency. The rewrite is per-command — `rtk` decides
|
|
12
|
-
* which programs it knows how to filter and falls back to the raw command
|
|
13
|
-
* for unknown programs (exit 1, no output → original used).
|
|
14
|
-
*
|
|
15
|
-
* Defaults to `false` so non-CLI embedders keep raw shell semantics.
|
|
16
|
-
* `@noetic/cli` opts in via `createDefaultShellAdapter`.
|
|
17
|
-
*
|
|
18
|
-
* Resolved against `PATH` once at adapter creation; the result is exposed
|
|
19
|
-
* as `rtkAvailable` so callers can fail fast when this is required.
|
|
20
|
-
*/
|
|
21
|
-
useRtk?: boolean;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Local shell adapter — a `ShellAdapter` plus introspection for the rtk
|
|
25
|
-
* wrapping decision so the harness factory can verify the binary is present
|
|
26
|
-
* before it starts running tools.
|
|
27
|
-
*
|
|
28
|
-
* @public
|
|
29
|
-
*/
|
|
30
|
-
export interface LocalShellAdapter extends ShellAdapter {
|
|
31
|
-
/** Whether `rtk` was found on PATH at adapter creation time. */
|
|
32
|
-
readonly rtkAvailable: boolean;
|
|
33
|
-
/** Resolved absolute path to `rtk`, or `null` when not on PATH. */
|
|
34
|
-
readonly rtkPath: string | null;
|
|
35
|
-
/** Whether wrapping with rtk is enabled (the constructor option). */
|
|
36
|
-
readonly useRtk: boolean;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Create a `ShellAdapter` backed by the local system shell via `Bun.spawn`.
|
|
40
|
-
*
|
|
41
|
-
* Defaults to plain `sh -c` execution. Pass `{ useRtk: true }` to wrap each
|
|
42
|
-
* command through `rtk rewrite` for token efficiency — best-effort: any
|
|
43
|
-
* failure (rtk missing, exit 1, timeout) falls through to the raw command.
|
|
44
|
-
* The CLI opts in via `createDefaultShellAdapter`; other embedders of
|
|
45
|
-
* `@noetic-tools/core` keep raw shell semantics unless they explicitly enable rtk.
|
|
46
|
-
*
|
|
47
|
-
* Call sites that want hard-fail semantics on missing rtk should read
|
|
48
|
-
* `rtkAvailable` on the returned adapter and refuse to boot when it is
|
|
49
|
-
* `false`.
|
|
50
|
-
*/
|
|
51
|
-
export declare function createLocalShellAdapter(opts?: CreateLocalShellAdapterOptions): LocalShellAdapter;
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import { TIMEOUT_ERROR_PREFIX } from '../types/shell-adapter';
|
|
2
|
-
//#endregion
|
|
3
|
-
//#region Helpers
|
|
4
|
-
const RTK_REWRITE_TIMEOUT_MS = 2e3;
|
|
5
|
-
function readStream(stream, onData) {
|
|
6
|
-
const chunks = [];
|
|
7
|
-
const reader = stream.getReader();
|
|
8
|
-
async function pump() {
|
|
9
|
-
while (true) {
|
|
10
|
-
const { done, value } = await reader.read();
|
|
11
|
-
if (done) {
|
|
12
|
-
break;
|
|
13
|
-
}
|
|
14
|
-
const buf = Buffer.from(value);
|
|
15
|
-
chunks.push(buf);
|
|
16
|
-
onData?.(buf);
|
|
17
|
-
}
|
|
18
|
-
return Buffer.concat(chunks).toString('utf-8');
|
|
19
|
-
}
|
|
20
|
-
return pump();
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Ask `rtk rewrite` to translate the raw command into its filtered form.
|
|
24
|
-
*
|
|
25
|
-
* Returns the rewritten command string when rtk knows how to wrap it
|
|
26
|
-
* (exit 0, non-empty stdout). Returns `null` on any other outcome — exit 1
|
|
27
|
-
* (rtk doesn't recognize the program), timeout, spawn failure — so the
|
|
28
|
-
* caller falls through to the raw command. This mirrors the documented
|
|
29
|
-
* hook contract: `REWRITTEN=$(rtk rewrite "$CMD") || exit 0`.
|
|
30
|
-
*/
|
|
31
|
-
async function rewriteWithRtk(rtkPath, command) {
|
|
32
|
-
try {
|
|
33
|
-
const proc = Bun.spawn([
|
|
34
|
-
rtkPath,
|
|
35
|
-
'rewrite',
|
|
36
|
-
command,
|
|
37
|
-
], {
|
|
38
|
-
stdout: 'pipe',
|
|
39
|
-
stderr: 'ignore',
|
|
40
|
-
});
|
|
41
|
-
const timeoutHandle = setTimeout(() => {
|
|
42
|
-
proc.kill();
|
|
43
|
-
}, RTK_REWRITE_TIMEOUT_MS);
|
|
44
|
-
try {
|
|
45
|
-
const [stdout, exitCode] = await Promise.all([
|
|
46
|
-
readStream(proc.stdout),
|
|
47
|
-
proc.exited,
|
|
48
|
-
]);
|
|
49
|
-
if (exitCode !== 0) {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
const trimmed = stdout.trim();
|
|
53
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
54
|
-
}
|
|
55
|
-
finally {
|
|
56
|
-
clearTimeout(timeoutHandle);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
//#endregion
|
|
64
|
-
//#region Public API
|
|
65
|
-
/**
|
|
66
|
-
* Create a `ShellAdapter` backed by the local system shell via `Bun.spawn`.
|
|
67
|
-
*
|
|
68
|
-
* Defaults to plain `sh -c` execution. Pass `{ useRtk: true }` to wrap each
|
|
69
|
-
* command through `rtk rewrite` for token efficiency — best-effort: any
|
|
70
|
-
* failure (rtk missing, exit 1, timeout) falls through to the raw command.
|
|
71
|
-
* The CLI opts in via `createDefaultShellAdapter`; other embedders of
|
|
72
|
-
* `@noetic-tools/core` keep raw shell semantics unless they explicitly enable rtk.
|
|
73
|
-
*
|
|
74
|
-
* Call sites that want hard-fail semantics on missing rtk should read
|
|
75
|
-
* `rtkAvailable` on the returned adapter and refuse to boot when it is
|
|
76
|
-
* `false`.
|
|
77
|
-
*/
|
|
78
|
-
export function createLocalShellAdapter(opts) {
|
|
79
|
-
const useRtk = opts?.useRtk ?? false;
|
|
80
|
-
// Read PATH from process.env so tests can override it. `Bun.which(name)`
|
|
81
|
-
// without an explicit PATH ignores subsequent process.env.PATH mutations.
|
|
82
|
-
const rtkPath = useRtk
|
|
83
|
-
? (Bun.which('rtk', {
|
|
84
|
-
PATH: process.env.PATH ?? '',
|
|
85
|
-
}) ?? null)
|
|
86
|
-
: null;
|
|
87
|
-
const rtkAvailable = rtkPath !== null;
|
|
88
|
-
async function exec(command, options) {
|
|
89
|
-
let effectiveCommand = command;
|
|
90
|
-
if (useRtk && rtkPath) {
|
|
91
|
-
const rewritten = await rewriteWithRtk(rtkPath, command);
|
|
92
|
-
if (rewritten) {
|
|
93
|
-
effectiveCommand = rewritten;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
const proc = Bun.spawn([
|
|
97
|
-
'sh',
|
|
98
|
-
'-c',
|
|
99
|
-
effectiveCommand,
|
|
100
|
-
], {
|
|
101
|
-
cwd: options.cwd,
|
|
102
|
-
env: options.env
|
|
103
|
-
? {
|
|
104
|
-
...process.env,
|
|
105
|
-
...options.env,
|
|
106
|
-
}
|
|
107
|
-
: undefined,
|
|
108
|
-
stdin: options.stdin
|
|
109
|
-
? new Blob([
|
|
110
|
-
options.stdin,
|
|
111
|
-
])
|
|
112
|
-
: undefined,
|
|
113
|
-
stdout: 'pipe',
|
|
114
|
-
stderr: 'pipe',
|
|
115
|
-
});
|
|
116
|
-
let timedOut = false;
|
|
117
|
-
let timeoutHandle;
|
|
118
|
-
const timeoutSeconds = options.timeout;
|
|
119
|
-
if (timeoutSeconds !== undefined && timeoutSeconds > 0) {
|
|
120
|
-
timeoutHandle = setTimeout(() => {
|
|
121
|
-
timedOut = true;
|
|
122
|
-
proc.kill();
|
|
123
|
-
}, timeoutSeconds * 1e3);
|
|
124
|
-
}
|
|
125
|
-
const abortHandler = () => {
|
|
126
|
-
proc.kill();
|
|
127
|
-
};
|
|
128
|
-
if (options.signal) {
|
|
129
|
-
options.signal.addEventListener('abort', abortHandler, {
|
|
130
|
-
once: true,
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
try {
|
|
134
|
-
const [stdout, stderr] = await Promise.all([
|
|
135
|
-
readStream(proc.stdout, options.onData),
|
|
136
|
-
readStream(proc.stderr, options.onData),
|
|
137
|
-
]);
|
|
138
|
-
const exitCode = await proc.exited;
|
|
139
|
-
// Only timeout throws. Signal-driven aborts resolve normally so
|
|
140
|
-
// callers can decide via their own state whether the result is
|
|
141
|
-
// a real exit or a cancellation (see runUserShellCommand).
|
|
142
|
-
if (timedOut) {
|
|
143
|
-
throw new Error(`${TIMEOUT_ERROR_PREFIX}${timeoutSeconds}`);
|
|
144
|
-
}
|
|
145
|
-
return {
|
|
146
|
-
stdout,
|
|
147
|
-
stderr,
|
|
148
|
-
exitCode,
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
finally {
|
|
152
|
-
if (timeoutHandle) {
|
|
153
|
-
clearTimeout(timeoutHandle);
|
|
154
|
-
}
|
|
155
|
-
if (options.signal) {
|
|
156
|
-
options.signal.removeEventListener('abort', abortHandler);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return {
|
|
161
|
-
exec,
|
|
162
|
-
rtkAvailable,
|
|
163
|
-
rtkPath,
|
|
164
|
-
useRtk,
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
//#endregion
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { ChildProcess, SpawnOptions } from 'node:child_process';
|
|
2
|
-
import type { SubprocessAdapter } from '../types/subprocess-adapter';
|
|
3
|
-
export type SubprocessSignal = 'SIGTERM' | 'SIGSTOP' | 'SIGCONT';
|
|
4
|
-
export interface ProcessSignaller {
|
|
5
|
-
kill(target: number, signal: SubprocessSignal): void;
|
|
6
|
-
isAlive(pid: number): boolean;
|
|
7
|
-
startTime(pid: number): string | null;
|
|
8
|
-
}
|
|
9
|
-
export interface CreateLocalSubprocessAdapterOptions {
|
|
10
|
-
spawnFn?: (command: string, args: ReadonlyArray<string>, options: SpawnOptions) => Pick<ChildProcess, 'pid' | 'unref'> & {
|
|
11
|
-
on(event: 'error', listener: (err: Error) => void): unknown;
|
|
12
|
-
};
|
|
13
|
-
signaller?: ProcessSignaller;
|
|
14
|
-
}
|
|
15
|
-
export declare const defaultProcessSignaller: ProcessSignaller;
|
|
16
|
-
export declare function createLocalSubprocessAdapter(options?: CreateLocalSubprocessAdapterOptions): SubprocessAdapter;
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import { execFileSync, spawn } from 'node:child_process';
|
|
2
|
-
function isErrnoException(err) {
|
|
3
|
-
return typeof err === 'object' && err !== null && 'code' in err;
|
|
4
|
-
}
|
|
5
|
-
function readPidStartTime(pid) {
|
|
6
|
-
try {
|
|
7
|
-
const out = execFileSync('ps', [
|
|
8
|
-
'-p',
|
|
9
|
-
String(pid),
|
|
10
|
-
'-o',
|
|
11
|
-
'lstart=',
|
|
12
|
-
], {
|
|
13
|
-
stdio: [
|
|
14
|
-
'ignore',
|
|
15
|
-
'pipe',
|
|
16
|
-
'ignore',
|
|
17
|
-
],
|
|
18
|
-
encoding: 'utf8',
|
|
19
|
-
}).trim();
|
|
20
|
-
return out.length === 0 ? null : out;
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
export const defaultProcessSignaller = {
|
|
27
|
-
kill(target, signal) {
|
|
28
|
-
process.kill(target, signal);
|
|
29
|
-
},
|
|
30
|
-
isAlive(pid) {
|
|
31
|
-
try {
|
|
32
|
-
process.kill(pid, 0);
|
|
33
|
-
return true;
|
|
34
|
-
}
|
|
35
|
-
catch (err) {
|
|
36
|
-
return isErrnoException(err) && err.code === 'EPERM';
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
startTime(pid) {
|
|
40
|
-
return readPidStartTime(pid);
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
function nowIso() {
|
|
44
|
-
return new Date().toISOString();
|
|
45
|
-
}
|
|
46
|
-
export function createLocalSubprocessAdapter(options = {}) {
|
|
47
|
-
const signaller = options.signaller ?? defaultProcessSignaller;
|
|
48
|
-
const spawnFn = options.spawnFn ?? ((command, args, opts) => spawn(command, args.slice(), opts));
|
|
49
|
-
const handles = new Map();
|
|
50
|
-
async function save(handle) {
|
|
51
|
-
handles.set(handle.id, handle);
|
|
52
|
-
return handle;
|
|
53
|
-
}
|
|
54
|
-
async function patch(handle, status) {
|
|
55
|
-
return save({
|
|
56
|
-
...handle,
|
|
57
|
-
status,
|
|
58
|
-
updatedAt: nowIso(),
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
function pidFor(handle) {
|
|
62
|
-
return typeof handle.metadata?.pid === 'number' ? handle.metadata.pid : null;
|
|
63
|
-
}
|
|
64
|
-
return {
|
|
65
|
-
async spawn(request) {
|
|
66
|
-
let asyncSpawnError = null;
|
|
67
|
-
const child = spawnFn(request.command, request.args ?? [], {
|
|
68
|
-
cwd: request.cwd,
|
|
69
|
-
detached: request.detached ?? false,
|
|
70
|
-
stdio: 'ignore',
|
|
71
|
-
env: request.env
|
|
72
|
-
? {
|
|
73
|
-
...process.env,
|
|
74
|
-
...request.env,
|
|
75
|
-
}
|
|
76
|
-
: undefined,
|
|
77
|
-
});
|
|
78
|
-
child.on('error', (err) => {
|
|
79
|
-
asyncSpawnError = err;
|
|
80
|
-
});
|
|
81
|
-
child.unref();
|
|
82
|
-
if (child.pid === undefined || !signaller.isAlive(child.pid)) {
|
|
83
|
-
throw new Error(asyncSpawnError instanceof Error
|
|
84
|
-
? asyncSpawnError.message
|
|
85
|
-
: `Subprocess failed to start: ${request.command}`);
|
|
86
|
-
}
|
|
87
|
-
const now = nowIso();
|
|
88
|
-
return save({
|
|
89
|
-
id: `subprocess-${crypto.randomUUID()}`,
|
|
90
|
-
status: 'running',
|
|
91
|
-
startedAt: now,
|
|
92
|
-
updatedAt: now,
|
|
93
|
-
metadata: {
|
|
94
|
-
...(request.metadata ?? {}),
|
|
95
|
-
runtime: 'local',
|
|
96
|
-
pid: child.pid,
|
|
97
|
-
pidStarttime: signaller.startTime(child.pid),
|
|
98
|
-
command: request.command,
|
|
99
|
-
args: request.args ?? [],
|
|
100
|
-
cwd: request.cwd,
|
|
101
|
-
detached: request.detached ?? false,
|
|
102
|
-
},
|
|
103
|
-
});
|
|
104
|
-
},
|
|
105
|
-
async get(handleId) {
|
|
106
|
-
return handles.get(handleId) ?? null;
|
|
107
|
-
},
|
|
108
|
-
async stop(handleId, reason) {
|
|
109
|
-
const handle = handles.get(handleId);
|
|
110
|
-
if (!handle) {
|
|
111
|
-
return {
|
|
112
|
-
kind: 'not_found',
|
|
113
|
-
handleId,
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
const pid = pidFor(handle);
|
|
117
|
-
if (pid !== null) {
|
|
118
|
-
try {
|
|
119
|
-
signaller.kill(handle.metadata?.detached === true ? -pid : pid, 'SIGTERM');
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
/* process may already be gone */
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
const next = await patch({
|
|
126
|
-
...handle,
|
|
127
|
-
metadata: {
|
|
128
|
-
...(handle.metadata ?? {}),
|
|
129
|
-
stopReason: reason,
|
|
130
|
-
},
|
|
131
|
-
}, 'stopped');
|
|
132
|
-
return {
|
|
133
|
-
kind: 'stopped',
|
|
134
|
-
handleId,
|
|
135
|
-
handle: next,
|
|
136
|
-
};
|
|
137
|
-
},
|
|
138
|
-
async pause(handleId) {
|
|
139
|
-
const handle = handles.get(handleId);
|
|
140
|
-
if (!handle) {
|
|
141
|
-
return {
|
|
142
|
-
kind: 'not_found',
|
|
143
|
-
handleId,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
const pid = pidFor(handle);
|
|
147
|
-
if (pid === null) {
|
|
148
|
-
return {
|
|
149
|
-
kind: 'unsupported',
|
|
150
|
-
handle,
|
|
151
|
-
message: 'Subprocess handle has no pid metadata.',
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
signaller.kill(handle.metadata?.detached === true ? -pid : pid, 'SIGSTOP');
|
|
155
|
-
return {
|
|
156
|
-
kind: 'ok',
|
|
157
|
-
handle: await patch(handle, 'paused'),
|
|
158
|
-
};
|
|
159
|
-
},
|
|
160
|
-
async resume(handleId) {
|
|
161
|
-
const handle = handles.get(handleId);
|
|
162
|
-
if (!handle) {
|
|
163
|
-
return {
|
|
164
|
-
kind: 'not_found',
|
|
165
|
-
handleId,
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
const pid = pidFor(handle);
|
|
169
|
-
if (pid === null) {
|
|
170
|
-
return {
|
|
171
|
-
kind: 'unsupported',
|
|
172
|
-
handle,
|
|
173
|
-
message: 'Subprocess handle has no pid metadata.',
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
signaller.kill(handle.metadata?.detached === true ? -pid : pid, 'SIGCONT');
|
|
177
|
-
return {
|
|
178
|
-
kind: 'ok',
|
|
179
|
-
handle: await patch(handle, 'running'),
|
|
180
|
-
};
|
|
181
|
-
},
|
|
182
|
-
async isAlive(handle) {
|
|
183
|
-
const pid = pidFor(handle);
|
|
184
|
-
return pid !== null && signaller.isAlive(pid);
|
|
185
|
-
},
|
|
186
|
-
};
|
|
187
|
-
}
|