experimental-ash 0.22.2 → 0.24.0
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 +36 -0
- package/dist/docs/internals/hooks.md +13 -16
- package/dist/docs/internals/message-runtime.md +1 -1
- package/dist/docs/public/auth-and-route-protection.md +3 -3
- package/dist/docs/public/faqs.md +67 -0
- package/dist/docs/public/meta.json +1 -0
- package/dist/docs/public/schedules.md +11 -0
- package/dist/docs/public/session-context.md +46 -89
- package/dist/docs/public/skills.md +13 -0
- package/dist/docs/public/subagents.md +12 -6
- package/dist/docs/public/tools.md +9 -13
- package/dist/docs/public/typescript-api.md +4 -4
- package/dist/src/channel/types.d.ts +10 -12
- package/dist/src/chunks/{client-CKsU8Li3.js → client-nshDsWNF.js} +1 -1
- package/dist/src/chunks/{dev-authored-source-watcher-BLzYWh05.js → dev-authored-source-watcher-B4PaZGUr.js} +1 -1
- package/dist/src/chunks/host-DsW72Q-w.js +65 -0
- package/dist/src/chunks/paths-OknjaYR8.js +89 -0
- package/dist/src/chunks/prewarm-B4YblQ5m.js +6 -0
- package/dist/src/cli/commands/info.js +1 -1
- package/dist/src/cli/dev/repl.js +2 -2
- package/dist/src/cli/run.js +1 -1
- package/dist/src/client/session.js +8 -0
- package/dist/src/client/types.d.ts +12 -1
- package/dist/src/compiled/.vendor-stamp.json +3 -3
- package/dist/src/compiled/@workflow/core/_ms.d.ts +4 -0
- package/dist/src/compiled/@workflow/core/_workflow-serde.d.ts +5 -0
- package/dist/src/compiled/@workflow/core/_workflow-utils.d.ts +8 -0
- package/dist/src/compiled/@workflow/core/_workflow-world.d.ts +59 -0
- package/dist/src/compiled/@workflow/core/capabilities.d.ts +45 -0
- package/dist/src/compiled/@workflow/core/capture-stack.d.ts +16 -0
- package/dist/src/compiled/@workflow/core/class-serialization.d.ts +31 -0
- package/dist/src/compiled/@workflow/core/classify-error.d.ts +20 -0
- package/dist/src/compiled/@workflow/core/context-errors.d.ts +27 -0
- package/dist/src/compiled/@workflow/core/context-violation-error.d.ts +97 -0
- package/dist/src/compiled/@workflow/core/create-hook.d.ts +179 -0
- package/dist/src/compiled/@workflow/core/define-hook.d.ts +68 -0
- package/dist/src/compiled/@workflow/core/describe-error.d.ts +70 -0
- package/dist/src/compiled/@workflow/core/encryption.d.ts +51 -0
- package/dist/src/compiled/@workflow/core/events-consumer.d.ts +64 -0
- package/dist/src/compiled/@workflow/core/flushable-stream.d.ts +82 -0
- package/dist/src/compiled/@workflow/core/global.d.ts +48 -0
- package/dist/src/compiled/@workflow/core/index.d.ts +19 -38
- package/dist/src/compiled/@workflow/core/index.js +2 -2
- package/dist/src/compiled/@workflow/core/log-format.d.ts +25 -0
- package/dist/src/compiled/@workflow/core/logger.d.ts +29 -0
- package/dist/src/compiled/@workflow/core/package.json +1 -1
- package/dist/src/compiled/@workflow/core/private.d.ts +59 -10
- package/dist/src/compiled/@workflow/core/runtime/constants.d.ts +51 -0
- package/dist/src/compiled/@workflow/core/runtime/get-port-lazy.d.ts +10 -0
- package/dist/src/compiled/@workflow/core/runtime/get-world-lazy.d.ts +32 -0
- package/dist/src/compiled/@workflow/core/runtime/helpers.d.ts +97 -0
- package/dist/src/compiled/@workflow/core/runtime/replay-budget.d.ts +98 -0
- package/dist/src/compiled/@workflow/core/runtime/resume-hook.d.ts +77 -0
- package/dist/src/compiled/@workflow/core/runtime/run.d.ts +134 -0
- package/dist/src/compiled/@workflow/core/runtime/runs.d.ts +50 -0
- package/dist/src/compiled/@workflow/core/runtime/start.d.ts +59 -0
- package/dist/src/compiled/@workflow/core/runtime/step-executor.d.ts +40 -0
- package/dist/src/compiled/@workflow/core/runtime/step-handler.d.ts +2 -0
- package/dist/src/compiled/@workflow/core/runtime/suspension-handler.d.ts +42 -0
- package/dist/src/compiled/@workflow/core/runtime/world-init.d.ts +75 -0
- package/dist/src/compiled/@workflow/core/runtime/world.d.ts +32 -0
- package/dist/src/compiled/@workflow/core/runtime.d.ts +22 -67
- package/dist/src/compiled/@workflow/core/runtime.js +27 -27
- package/dist/src/compiled/@workflow/core/schemas.d.ts +15 -0
- package/dist/src/compiled/@workflow/core/serialization/client.d.ts +17 -0
- package/dist/src/compiled/@workflow/core/serialization/codec-devalue.d.ts +14 -0
- package/dist/src/compiled/@workflow/core/serialization/codec.d.ts +90 -0
- package/dist/src/compiled/@workflow/core/serialization/encryption.d.ts +32 -0
- package/dist/src/compiled/@workflow/core/serialization/errors.d.ts +21 -0
- package/dist/src/compiled/@workflow/core/serialization/format.d.ts +60 -0
- package/dist/src/compiled/@workflow/core/serialization/index.d.ts +18 -0
- package/dist/src/compiled/@workflow/core/serialization/reducers/class.d.ts +11 -0
- package/dist/src/compiled/@workflow/core/serialization/reducers/common.d.ts +16 -0
- package/dist/src/compiled/@workflow/core/serialization/reducers/step-function.d.ts +35 -0
- package/dist/src/compiled/@workflow/core/serialization/step.d.ts +17 -0
- package/dist/src/compiled/@workflow/core/serialization/types.d.ts +215 -0
- package/dist/src/compiled/@workflow/core/serialization/workflow.d.ts +29 -0
- package/dist/src/compiled/@workflow/core/serialization-format.d.ts +171 -0
- package/dist/src/compiled/@workflow/core/serialization.d.ts +337 -0
- package/dist/src/compiled/@workflow/core/sleep.d.ts +33 -0
- package/dist/src/compiled/@workflow/core/source-map.d.ts +10 -0
- package/dist/src/compiled/@workflow/core/step/context-storage.d.ts +13 -0
- package/dist/src/compiled/@workflow/core/step/get-closure-vars.d.ts +9 -0
- package/dist/src/compiled/@workflow/core/step/get-step-metadata.d.ts +42 -0
- package/dist/src/compiled/@workflow/core/step/get-workflow-metadata.d.ts +7 -0
- package/dist/src/compiled/@workflow/core/step/writable-stream.d.ts +22 -0
- package/dist/src/compiled/@workflow/core/step.d.ts +4 -0
- package/dist/src/compiled/@workflow/core/symbols.d.ts +36 -0
- package/dist/src/compiled/@workflow/core/telemetry/semantic-conventions.d.ts +283 -0
- package/dist/src/compiled/@workflow/core/telemetry.d.ts +53 -0
- package/dist/src/compiled/@workflow/core/types.d.ts +14 -0
- package/dist/src/compiled/@workflow/core/util.d.ts +40 -0
- package/dist/src/compiled/@workflow/core/version.d.ts +2 -0
- package/dist/src/compiled/@workflow/core/vm/index.d.ts +17 -0
- package/dist/src/compiled/@workflow/core/vm/uint8array-base64.d.ts +21 -0
- package/dist/src/compiled/@workflow/core/vm/uuid.d.ts +10 -0
- package/dist/src/compiled/@workflow/core/workflow/abort-controller.d.ts +65 -0
- package/dist/src/compiled/@workflow/core/workflow/create-hook.d.ts +7 -0
- package/dist/src/compiled/@workflow/core/workflow/define-hook.d.ts +10 -0
- package/dist/src/compiled/@workflow/core/workflow/get-workflow-metadata.d.ts +32 -0
- package/dist/src/compiled/@workflow/core/workflow/hook.d.ts +4 -0
- package/dist/src/compiled/@workflow/core/workflow/index.d.ts +11 -0
- package/dist/src/compiled/@workflow/core/workflow/sleep.d.ts +4 -0
- package/dist/src/compiled/@workflow/core/workflow/world-init-stub.d.ts +15 -0
- package/dist/src/compiled/@workflow/core/workflow/writable-stream.d.ts +3 -0
- package/dist/src/compiled/@workflow/core/workflow.d.ts +1 -38
- package/dist/src/compiled/@workflow/core/workflow.js +1 -1
- package/dist/src/compiled/@workflow/errors/error-codes.d.ts +5 -1
- package/dist/src/compiled/@workflow/errors/index.d.ts +15 -1
- package/dist/src/compiled/@workflow/errors/index.js +1 -1
- package/dist/src/compiled/@workflow/errors/package.json +1 -1
- package/dist/src/compiled/_chunks/workflow/{context-errors-zbKocOyk.js → context-errors-Bbvvp-li.js} +2 -2
- package/dist/src/compiled/_chunks/workflow/{dist-0iNBqPYp.js → dist-C7wPwOI9.js} +2 -2
- package/dist/src/compiled/_chunks/workflow/{dist-D774SUM4.js → dist-C_oiE-l7.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/resume-hook-C3VWUPii.js +12 -0
- package/dist/src/compiled/_chunks/workflow/sleep-QTkC1VFe.js +1 -0
- package/dist/src/compiled/_chunks/workflow/{symbols-D-4tVV8x.js → symbols-QezhMuLg.js} +1 -1
- package/dist/src/evals/cli/eval.js +1 -1
- package/dist/src/execution/await-authorization-orchestrator.d.ts +2 -1
- package/dist/src/execution/await-authorization-orchestrator.js +4 -0
- package/dist/src/execution/connection-auth-steps.d.ts +4 -0
- package/dist/src/execution/connection-auth-steps.js +9 -11
- package/dist/src/execution/node-step.d.ts +4 -5
- package/dist/src/execution/subagent-adapter.d.ts +0 -27
- package/dist/src/execution/subagent-adapter.js +2 -66
- package/dist/src/execution/subagent-hitl-proxy.d.ts +2 -2
- package/dist/src/execution/subagent-hitl-proxy.js +2 -2
- package/dist/src/execution/task-mode.d.ts +3 -3
- package/dist/src/execution/task-mode.js +3 -3
- package/dist/src/execution/turn-workflow.d.ts +41 -0
- package/dist/src/execution/turn-workflow.js +96 -0
- package/dist/src/execution/workflow-entry.js +77 -87
- package/dist/src/execution/workflow-errors.d.ts +14 -0
- package/dist/src/execution/workflow-errors.js +54 -0
- package/dist/src/execution/workflow-runtime.d.ts +34 -3
- package/dist/src/execution/workflow-runtime.js +52 -10
- package/dist/src/execution/workflow-steps.d.ts +27 -2
- package/dist/src/execution/workflow-steps.js +31 -26
- package/dist/src/harness/instrumentation-config.js +14 -7
- package/dist/src/harness/messages.d.ts +7 -7
- package/dist/src/harness/messages.js +4 -4
- package/dist/src/harness/runtime-actions.d.ts +4 -4
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/workflow-bundle/workflow-builders.d.ts +1 -1
- package/dist/src/internal/workflow-bundle/workflow-builders.js +20 -8
- package/dist/src/internal/workflow-bundle/workflow-transformer.d.ts +13 -0
- package/dist/src/internal/workflow-bundle/workflow-transformer.js +10 -4
- package/dist/src/protocol/message.d.ts +6 -1
- package/dist/src/public/channels/ash.js +50 -3
- package/dist/src/public/context/index.d.ts +4 -7
- package/dist/src/public/context/index.js +4 -5
- package/dist/src/public/definitions/state.d.ts +33 -0
- package/dist/src/public/definitions/state.js +34 -0
- package/dist/src/public/next/index.d.ts +7 -0
- package/dist/src/public/next/index.js +2 -0
- package/dist/src/public/next/vercel-json.d.ts +1 -0
- package/dist/src/public/next/vercel-json.js +1 -0
- package/dist/src/react/index.d.ts +1 -1
- package/dist/src/react/use-ash-agent.d.ts +8 -0
- package/dist/src/react/use-ash-agent.js +26 -4
- package/dist/src/services/dev-client.d.ts +4 -1
- package/dist/src/services/dev-client.js +1 -0
- package/package.json +4 -4
- package/dist/src/chunks/host-DREC8e8Z.js +0 -65
- package/dist/src/chunks/paths-C6sp4T2U.js +0 -88
- package/dist/src/chunks/prewarm-hz8p2jlZ.js +0 -6
- package/dist/src/compiled/_chunks/workflow/resume-hook-CL8Ed91K.js +0 -12
- package/dist/src/compiled/_chunks/workflow/sleep-Dn3i9nxI.js +0 -1
- package/dist/src/execution/continuous-entry.d.ts +0 -59
- package/dist/src/execution/continuous-entry.js +0 -487
- package/dist/src/execution/continuous-runtime.d.ts +0 -17
- package/dist/src/execution/continuous-runtime.js +0 -123
|
@@ -2,11 +2,22 @@ import type { DeliverPayload, HookPayload, SessionAuthContext, SubagentInputRequ
|
|
|
2
2
|
import { deserializeContext } from "#context/serialize.js";
|
|
3
3
|
import type { HarnessSession } from "#harness/types.js";
|
|
4
4
|
import type { RuntimeCompiledArtifactsSource } from "#runtime/compiled-artifacts-source.js";
|
|
5
|
+
import { type TurnWorkflowInput } from "#execution/turn-workflow.js";
|
|
5
6
|
import type { DurableStepResult } from "#execution/types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Input for one atomic harness step inside a durable `"use step"`
|
|
9
|
+
* boundary.
|
|
10
|
+
*/
|
|
11
|
+
export interface TurnStepInput {
|
|
12
|
+
readonly input: HookPayload | undefined;
|
|
13
|
+
readonly parentWritable: WritableStream<Uint8Array>;
|
|
14
|
+
readonly serializedContext: Record<string, unknown>;
|
|
15
|
+
readonly session: HarnessSession;
|
|
16
|
+
}
|
|
6
17
|
/**
|
|
7
18
|
* Runs one atomic harness step inside a durable `"use step"` boundary.
|
|
8
19
|
*/
|
|
9
|
-
export declare function
|
|
20
|
+
export declare function turnStep(input: TurnStepInput): Promise<DurableStepResult>;
|
|
10
21
|
/**
|
|
11
22
|
* Reconciles `session.continuationToken` with the live
|
|
12
23
|
* `ContinuationTokenKey` value in context.
|
|
@@ -30,6 +41,7 @@ export declare function reconcileSessionContinuationToken(ctx: Awaited<ReturnTyp
|
|
|
30
41
|
* runs independently on its own public child stream.
|
|
31
42
|
*/
|
|
32
43
|
export declare function dispatchPendingRuntimeActionsStep(input: {
|
|
44
|
+
readonly parentWritable: WritableStream<Uint8Array>;
|
|
33
45
|
readonly serializedContext: Record<string, unknown>;
|
|
34
46
|
readonly session: HarnessSession;
|
|
35
47
|
}): Promise<HarnessSession>;
|
|
@@ -38,8 +50,9 @@ export declare function dispatchPendingRuntimeActionsStep(input: {
|
|
|
38
50
|
* adapter before the workflow run tears down.
|
|
39
51
|
*/
|
|
40
52
|
export declare function emitTerminalSessionFailureStep(input: {
|
|
41
|
-
readonly serializedContext: Record<string, unknown>;
|
|
42
53
|
readonly error: unknown;
|
|
54
|
+
readonly parentWritable: WritableStream<Uint8Array>;
|
|
55
|
+
readonly serializedContext: Record<string, unknown>;
|
|
43
56
|
}): Promise<void>;
|
|
44
57
|
/**
|
|
45
58
|
* Outcome of {@link runProxyInputRequestStep}, including the session
|
|
@@ -55,6 +68,7 @@ export interface RunProxyInputRequestResult {
|
|
|
55
68
|
*/
|
|
56
69
|
export declare function runProxyInputRequestStep(input: {
|
|
57
70
|
readonly hookPayload: SubagentInputRequestHookPayload;
|
|
71
|
+
readonly parentWritable: WritableStream<Uint8Array>;
|
|
58
72
|
readonly serializedContext: Record<string, unknown>;
|
|
59
73
|
readonly session: HarnessSession;
|
|
60
74
|
}): Promise<RunProxyInputRequestResult>;
|
|
@@ -81,9 +95,20 @@ export interface RoutedProxiedDeliverResult {
|
|
|
81
95
|
*/
|
|
82
96
|
export declare function routeProxiedDeliverStep(input: {
|
|
83
97
|
readonly auth?: SessionAuthContext | null;
|
|
98
|
+
readonly parentWritable: WritableStream<Uint8Array>;
|
|
84
99
|
readonly payload: DeliverPayload;
|
|
85
100
|
readonly session: HarnessSession;
|
|
86
101
|
}): Promise<RoutedProxiedDeliverResult>;
|
|
102
|
+
/**
|
|
103
|
+
* Starts a per-turn child workflow for the current driver session.
|
|
104
|
+
*
|
|
105
|
+
* `parentWritable` is forwarded to the child in the workflow input so
|
|
106
|
+
* the child's step writes land directly on the driver run's stream —
|
|
107
|
+
* no copier, no double-store.
|
|
108
|
+
*/
|
|
109
|
+
export declare function dispatchTurnStep(input: TurnWorkflowInput): Promise<{
|
|
110
|
+
readonly runId: string;
|
|
111
|
+
}>;
|
|
87
112
|
/**
|
|
88
113
|
* Creates the durable session state inside a step boundary before the
|
|
89
114
|
* workflow enters its long-lived turn loop.
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { getWritable } from "#compiled/@workflow/core/index.js";
|
|
2
1
|
import { buildAdapterContext } from "#channel/adapter-context.js";
|
|
3
2
|
import { callAdapterEventHandler, defaultDeliverResult } from "#channel/adapter.js";
|
|
4
3
|
import { toContextAccessor } from "#context/container.js";
|
|
@@ -19,20 +18,21 @@ import { createExecutionNodeStep } from "#execution/node-step.js";
|
|
|
19
18
|
import { emitProxiedInputRequest, routeDeliverPayload } from "#execution/subagent-hitl-proxy.js";
|
|
20
19
|
import { createSession, refreshSessionFromTurnAgent } from "#execution/session.js";
|
|
21
20
|
import { buildSubagentRunInput } from "#execution/subagent-tool.js";
|
|
22
|
-
import {
|
|
21
|
+
import { turnWorkflow } from "#execution/turn-workflow.js";
|
|
22
|
+
import { createWorkflowRuntime, startWorkflowPreferLatest, workflowEntryReference, } from "#execution/workflow-runtime.js";
|
|
23
23
|
/**
|
|
24
24
|
* Runs one atomic harness step inside a durable `"use step"` boundary.
|
|
25
25
|
*/
|
|
26
|
-
export async function
|
|
26
|
+
export async function turnStep(input) {
|
|
27
27
|
"use step";
|
|
28
|
-
const ctx = await deserializeContext(serializedContext);
|
|
28
|
+
const ctx = await deserializeContext(input.serializedContext);
|
|
29
29
|
const adapter = ctx.require(ChannelKey);
|
|
30
30
|
// Apply deliver-time auth if present. The auth traveled through
|
|
31
31
|
// resumeHook as JSON on the HookPayload. On the first turn (from
|
|
32
32
|
// run()), input carries no auth because it was already seeded by
|
|
33
33
|
// buildRunContext.
|
|
34
|
-
if (input?.kind === "deliver" && input.auth !== undefined) {
|
|
35
|
-
ctx.set(AuthKey, input.auth ?? null);
|
|
34
|
+
if (input.input?.kind === "deliver" && input.input.auth !== undefined) {
|
|
35
|
+
ctx.set(AuthKey, input.input.auth ?? null);
|
|
36
36
|
}
|
|
37
37
|
// Build the adapter context for deliver and event handlers.
|
|
38
38
|
// Slack adapters override this to inject ctx.thread and ctx.slack.
|
|
@@ -41,9 +41,9 @@ export async function durableRunStep(serializedContext, session, input) {
|
|
|
41
41
|
// custom context keys and optionally transforms the message.
|
|
42
42
|
// Coalesces the resulting StepInput values.
|
|
43
43
|
let resolved;
|
|
44
|
-
if (input?.kind === "deliver") {
|
|
44
|
+
if (input.input?.kind === "deliver") {
|
|
45
45
|
const results = [];
|
|
46
|
-
for (const payload of input.payloads) {
|
|
46
|
+
for (const payload of input.input.payloads) {
|
|
47
47
|
const result = adapter.deliver
|
|
48
48
|
? await adapter.deliver(payload, adapterCtx)
|
|
49
49
|
: defaultDeliverResult(payload);
|
|
@@ -53,31 +53,27 @@ export async function durableRunStep(serializedContext, session, input) {
|
|
|
53
53
|
}
|
|
54
54
|
resolved = results.length === 0 ? undefined : results.reduce(coalesceTurnInputs);
|
|
55
55
|
}
|
|
56
|
-
else if (input?.kind === "runtime-action-result") {
|
|
57
|
-
resolved = { runtimeActionResults: input.results };
|
|
56
|
+
else if (input.input?.kind === "runtime-action-result") {
|
|
57
|
+
resolved = { runtimeActionResults: input.input.results };
|
|
58
58
|
}
|
|
59
59
|
// Update adapter state on context after deliver mutations.
|
|
60
|
-
if (input?.kind === "deliver") {
|
|
60
|
+
if (input.input?.kind === "deliver") {
|
|
61
61
|
const updatedAdapter = { ...adapter, state: { ...adapterCtx.state } };
|
|
62
62
|
ctx.set(ChannelKey, updatedAdapter);
|
|
63
63
|
}
|
|
64
64
|
// Adapter handled the delivery inline (e.g. a Slack interaction that
|
|
65
65
|
// only edits a message). Persist any context mutations and re-park
|
|
66
66
|
// without running a model turn.
|
|
67
|
-
if (input?.kind === "deliver" && resolved === undefined) {
|
|
68
|
-
const rekeyed = reconcileSessionContinuationToken(ctx, session);
|
|
67
|
+
if (input.input?.kind === "deliver" && resolved === undefined) {
|
|
68
|
+
const rekeyed = reconcileSessionContinuationToken(ctx, input.session);
|
|
69
69
|
const nextSerializedContext = serializeContext(ctx);
|
|
70
|
-
const writable = getWritable();
|
|
71
|
-
const writer = writable.getWriter();
|
|
72
|
-
writer.releaseLock();
|
|
73
70
|
return {
|
|
74
71
|
action: "park",
|
|
75
72
|
serializedContext: nextSerializedContext,
|
|
76
73
|
session: rekeyed,
|
|
77
74
|
};
|
|
78
75
|
}
|
|
79
|
-
const
|
|
80
|
-
const writer = writable.getWriter();
|
|
76
|
+
const writer = input.parentWritable.getWriter();
|
|
81
77
|
const hookRegistry = ctx.require(BundleKey).hookRegistry;
|
|
82
78
|
const emit = async (event) => {
|
|
83
79
|
const toEmit = await callAdapterEventHandler(adapter, event, adapterCtx);
|
|
@@ -85,7 +81,7 @@ export async function durableRunStep(serializedContext, session, input) {
|
|
|
85
81
|
await writer.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(toEmit)));
|
|
86
82
|
await dispatchStreamEventHooks({ ctx, registry: hookRegistry, event: toEmit });
|
|
87
83
|
};
|
|
88
|
-
let stepResult = await runStep(ctx, session, async (enrichedSession) => {
|
|
84
|
+
let stepResult = await runStep(ctx, input.session, async (enrichedSession) => {
|
|
89
85
|
const bundle = ctx.require(BundleKey);
|
|
90
86
|
const capabilities = ctx.get(CapabilitiesKey);
|
|
91
87
|
const mode = ctx.require(ModeKey);
|
|
@@ -223,8 +219,7 @@ export async function dispatchPendingRuntimeActionsStep(input) {
|
|
|
223
219
|
const auth = ctx.get(AuthKey) ?? null;
|
|
224
220
|
const capabilities = ctx.get(CapabilitiesKey);
|
|
225
221
|
const initiatorAuth = ctx.get(InitiatorAuthKey) ?? null;
|
|
226
|
-
const
|
|
227
|
-
const writer = writable.getWriter();
|
|
222
|
+
const writer = input.parentWritable.getWriter();
|
|
228
223
|
const adapterCtx = buildAdapterContext(adapter, toContextAccessor(ctx));
|
|
229
224
|
let nextSession = input.session;
|
|
230
225
|
try {
|
|
@@ -308,8 +303,7 @@ export async function emitTerminalSessionFailureStep(input) {
|
|
|
308
303
|
// consumers (client SDK readers, event-stream replays, dashboards)
|
|
309
304
|
// see a canonical terminal event instead of an abrupt stream close.
|
|
310
305
|
try {
|
|
311
|
-
const
|
|
312
|
-
const writer = writable.getWriter();
|
|
306
|
+
const writer = input.parentWritable.getWriter();
|
|
313
307
|
try {
|
|
314
308
|
await writer.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(event)));
|
|
315
309
|
}
|
|
@@ -335,8 +329,7 @@ export async function runProxyInputRequestStep(input) {
|
|
|
335
329
|
const adapter = ctx.require(ChannelKey);
|
|
336
330
|
const adapterCtx = buildAdapterContext(adapter, toContextAccessor(ctx));
|
|
337
331
|
const mode = ctx.require(ModeKey);
|
|
338
|
-
const
|
|
339
|
-
const writer = writable.getWriter();
|
|
332
|
+
const writer = input.parentWritable.getWriter();
|
|
340
333
|
let proxyResult;
|
|
341
334
|
try {
|
|
342
335
|
const emit = async (event) => {
|
|
@@ -355,7 +348,7 @@ export async function runProxyInputRequestStep(input) {
|
|
|
355
348
|
}
|
|
356
349
|
// Persist adapter-state mutations (e.g. Slack's `pendingRequests`
|
|
357
350
|
// cache populated by the `input.requested` handler) so the next
|
|
358
|
-
// `
|
|
351
|
+
// `turnStep` observes them across the serialized context
|
|
359
352
|
// boundary. Without this the workflow runtime rehydrates a stale
|
|
360
353
|
// adapter and later text-reply deliveries miss the cached batch.
|
|
361
354
|
ctx.set(ChannelKey, { ...adapter, state: { ...adapterCtx.state } });
|
|
@@ -396,6 +389,18 @@ export async function routeProxiedDeliverStep(input) {
|
|
|
396
389
|
}
|
|
397
390
|
return { remainder: routed.forSelf };
|
|
398
391
|
}
|
|
392
|
+
/**
|
|
393
|
+
* Starts a per-turn child workflow for the current driver session.
|
|
394
|
+
*
|
|
395
|
+
* `parentWritable` is forwarded to the child in the workflow input so
|
|
396
|
+
* the child's step writes land directly on the driver run's stream —
|
|
397
|
+
* no copier, no double-store.
|
|
398
|
+
*/
|
|
399
|
+
export async function dispatchTurnStep(input) {
|
|
400
|
+
"use step";
|
|
401
|
+
const run = await startWorkflowPreferLatest(turnWorkflow, [input]);
|
|
402
|
+
return { runId: run.runId };
|
|
403
|
+
}
|
|
399
404
|
/**
|
|
400
405
|
* Creates the durable session state inside a step boundary before the
|
|
401
406
|
* workflow enters its long-lived turn loop.
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Process-global store for the authored instrumentation config.
|
|
3
3
|
*
|
|
4
4
|
* Populated at server startup by the generated Nitro instrumentation plugin
|
|
5
5
|
* when the user's `agent/instrumentation.ts` has a default export produced
|
|
6
|
-
* by `defineInstrumentation()`.
|
|
6
|
+
* by `defineInstrumentation()`. The harness reads from this at turn time
|
|
7
|
+
* to decide whether telemetry is enabled and which settings to pass to the
|
|
8
|
+
* AI SDK.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
+
* Rooted on `globalThis` so the generated Nitro instrumentation plugin
|
|
11
|
+
* (which Nitro keeps external by `file://` URL) and the bundled harness
|
|
12
|
+
* chunk (which Nitro inlines via the package's `#harness/*` import alias)
|
|
13
|
+
* share one source of truth, even though they resolve to two distinct ESM
|
|
14
|
+
* module instances. See `context/key.ts` and
|
|
15
|
+
* `runtime/sessions/runtime-session.ts` for the established pattern.
|
|
10
16
|
*/
|
|
11
|
-
|
|
17
|
+
const INSTRUMENTATION_CONFIG_GLOBAL_KEY = Symbol.for("experimental-ash.harness-instrumentation-config");
|
|
18
|
+
const globalContainer = globalThis;
|
|
12
19
|
/**
|
|
13
20
|
* Registers the authored instrumentation config and invokes its `setup`
|
|
14
21
|
* callback with the resolved agent name.
|
|
@@ -22,7 +29,7 @@ export function registerInstrumentationConfig(config, context) {
|
|
|
22
29
|
if (config.setup !== undefined) {
|
|
23
30
|
config.setup(context);
|
|
24
31
|
}
|
|
25
|
-
|
|
32
|
+
globalContainer[INSTRUMENTATION_CONFIG_GLOBAL_KEY] = config;
|
|
26
33
|
}
|
|
27
34
|
/**
|
|
28
35
|
* Returns the registered instrumentation config, or `undefined` when no
|
|
@@ -31,5 +38,5 @@ export function registerInstrumentationConfig(config, context) {
|
|
|
31
38
|
* @internal — not part of the public API.
|
|
32
39
|
*/
|
|
33
40
|
export function getInstrumentationConfig() {
|
|
34
|
-
return
|
|
41
|
+
return globalContainer[INSTRUMENTATION_CONFIG_GLOBAL_KEY];
|
|
35
42
|
}
|
|
@@ -19,9 +19,9 @@ export declare function coalesceTurnInputs(a: StepInput, b: StepInput): StepInpu
|
|
|
19
19
|
*/
|
|
20
20
|
export declare function resolveAssistantStepText(messages: readonly ModelMessage[], fallback: string | undefined): string | null;
|
|
21
21
|
/**
|
|
22
|
-
* Structural shape
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* Structural shape of the workflow `DeliverHookPayload`. Using a
|
|
23
|
+
* structural type keeps this helper decoupled from the concrete
|
|
24
|
+
* runtime type.
|
|
25
25
|
*/
|
|
26
26
|
interface DeliverLike {
|
|
27
27
|
readonly auth?: SessionAuthContext | null;
|
|
@@ -32,10 +32,10 @@ interface DeliverLike {
|
|
|
32
32
|
* Coalesces an array of deliver-like items into a single item by
|
|
33
33
|
* collecting all payloads and keeping the most recent auth value.
|
|
34
34
|
*
|
|
35
|
-
* Used by
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
35
|
+
* Used by the workflow runtime to batch follow-up deliveries that
|
|
36
|
+
* arrived while a turn or subagent delegation was in progress. Each
|
|
37
|
+
* payload is later passed to `onDeliver` individually so channel-
|
|
38
|
+
* specific fields are never lost.
|
|
39
39
|
*/
|
|
40
40
|
export declare function coalesceDeliveries<T extends DeliverLike>(items: readonly T[]): T;
|
|
41
41
|
export {};
|
|
@@ -122,10 +122,10 @@ function toUserContentArray(value) {
|
|
|
122
122
|
* Coalesces an array of deliver-like items into a single item by
|
|
123
123
|
* collecting all payloads and keeping the most recent auth value.
|
|
124
124
|
*
|
|
125
|
-
* Used by
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
125
|
+
* Used by the workflow runtime to batch follow-up deliveries that
|
|
126
|
+
* arrived while a turn or subagent delegation was in progress. Each
|
|
127
|
+
* payload is later passed to `onDeliver` individually so channel-
|
|
128
|
+
* specific fields are never lost.
|
|
129
129
|
*/
|
|
130
130
|
export function coalesceDeliveries(items) {
|
|
131
131
|
const [first, ...rest] = items;
|
|
@@ -67,10 +67,10 @@ export declare function recordPendingSubagentChildToken(input: {
|
|
|
67
67
|
/**
|
|
68
68
|
* Discriminated item consumed by {@link accumulateRuntimeActionResults}.
|
|
69
69
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
70
|
+
* The workflow runtime receives interleaved deliveries and runtime-action
|
|
71
|
+
* results while waiting for pending subagent calls; this union lets the
|
|
72
|
+
* accumulation loop process both kinds without coupling to the concrete
|
|
73
|
+
* `HookPayload` shape.
|
|
74
74
|
*/
|
|
75
75
|
export type RuntimeActionAccumulatorItem<TDeliver> = {
|
|
76
76
|
readonly kind: "deliver";
|
|
@@ -6,7 +6,7 @@ import { ASH_PACKAGE_NAME } from "#package-name.js";
|
|
|
6
6
|
let cachedPackageInfo;
|
|
7
7
|
// The package build stamps the published version into `dist` so bundled
|
|
8
8
|
// deployments can still report package metadata without resolving package.json.
|
|
9
|
-
const BUNDLED_FALLBACK_PACKAGE_VERSION = "0.
|
|
9
|
+
const BUNDLED_FALLBACK_PACKAGE_VERSION = "0.24.0";
|
|
10
10
|
const BUNDLED_FALLBACK_PACKAGE_VERSION_PLACEHOLDER = "__ASH_PACKAGE_VERSION_PLACEHOLDER__";
|
|
11
11
|
const WORKFLOW_MODULE_ALIASES = {
|
|
12
12
|
"workflow/api": "src/compiled/@workflow/core/runtime.js",
|
|
@@ -28,7 +28,7 @@ export declare const WORKFLOW_QUEUE_TRIGGER: {
|
|
|
28
28
|
readonly retryAfterSeconds: 5;
|
|
29
29
|
readonly initialDelaySeconds: 0;
|
|
30
30
|
};
|
|
31
|
-
export declare function applyWorkflowTransform(filename: string, source: string, mode: "workflow" | "step" | "client" | false, absolutePath?: string, projectRoot?: string): Promise<{
|
|
31
|
+
export declare function applyWorkflowTransform(filename: string, source: string, mode: "workflow" | "step" | "client" | false, absolutePath?: string, projectRoot?: string, stableWorkflowNames?: ReadonlySet<string>): Promise<{
|
|
32
32
|
code: string;
|
|
33
33
|
workflowManifest: WorkflowManifest;
|
|
34
34
|
}>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { STABLE_WORKFLOW_NAMES } from "#execution/workflow-runtime.js";
|
|
4
5
|
import { transformWorkflowDirectives } from "./workflow-transformer.js";
|
|
5
6
|
export const WORKFLOW_QUEUE_TRIGGER = {
|
|
6
7
|
type: "queue/v2beta",
|
|
@@ -11,15 +12,22 @@ export const WORKFLOW_QUEUE_TRIGGER = {
|
|
|
11
12
|
};
|
|
12
13
|
const packageJsonCache = new Map();
|
|
13
14
|
const projectDepsCache = new Map();
|
|
14
|
-
export async function applyWorkflowTransform(filename, source, mode, absolutePath, projectRoot) {
|
|
15
|
+
export async function applyWorkflowTransform(filename, source, mode, absolutePath, projectRoot, stableWorkflowNames = STABLE_WORKFLOW_NAMES) {
|
|
15
16
|
const resolvedProjectRoot = projectRoot ?? process.cwd();
|
|
16
17
|
const absoluteFilename = absolutePath === undefined
|
|
17
18
|
? isAbsolute(filename)
|
|
18
19
|
? filename
|
|
19
20
|
: join(resolvedProjectRoot, filename)
|
|
20
21
|
: absolutePath;
|
|
21
|
-
const { moduleSpecifier } = resolveModuleSpecifier(absoluteFilename, resolvedProjectRoot);
|
|
22
|
-
return transformWorkflowDirectives({
|
|
22
|
+
const { moduleSpecifier, stableModuleSpecifier } = resolveModuleSpecifier(absoluteFilename, resolvedProjectRoot);
|
|
23
|
+
return transformWorkflowDirectives({
|
|
24
|
+
filename,
|
|
25
|
+
mode,
|
|
26
|
+
moduleSpecifier,
|
|
27
|
+
source,
|
|
28
|
+
stableModuleSpecifier,
|
|
29
|
+
stableWorkflowNames,
|
|
30
|
+
});
|
|
23
31
|
}
|
|
24
32
|
export function detectWorkflowPatterns(source) {
|
|
25
33
|
return {
|
|
@@ -58,17 +66,21 @@ function resolveModuleSpecifier(filePath, projectRoot) {
|
|
|
58
66
|
const inNodeModules = isInNodeModules(filePath);
|
|
59
67
|
const inWorkspace = !inNodeModules && isWorkspacePackage(filePath, projectRoot);
|
|
60
68
|
if (!inNodeModules && !inWorkspace) {
|
|
61
|
-
return { moduleSpecifier: undefined };
|
|
69
|
+
return { moduleSpecifier: undefined, stableModuleSpecifier: undefined };
|
|
62
70
|
}
|
|
63
71
|
const pkg = findPackageJson(filePath);
|
|
64
72
|
if (pkg === null) {
|
|
65
|
-
return { moduleSpecifier: undefined };
|
|
73
|
+
return { moduleSpecifier: undefined, stableModuleSpecifier: undefined };
|
|
66
74
|
}
|
|
67
75
|
const subpath = resolveExportSubpath(filePath, pkg);
|
|
76
|
+
// The default specifier is version-stamped for normal workflow/step
|
|
77
|
+
// ids; the stable variant drops the `@<pkg.version>` suffix so
|
|
78
|
+
// {@link STABLE_WORKFLOW_NAMES} functions emit cross-deployment
|
|
79
|
+
// routable ids.
|
|
80
|
+
const base = subpath ? `${pkg.name}${subpath}` : pkg.name;
|
|
68
81
|
return {
|
|
69
|
-
moduleSpecifier:
|
|
70
|
-
|
|
71
|
-
: `${pkg.name}@${pkg.version}`,
|
|
82
|
+
moduleSpecifier: `${base}@${pkg.version}`,
|
|
83
|
+
stableModuleSpecifier: base,
|
|
72
84
|
};
|
|
73
85
|
}
|
|
74
86
|
function findPackageJson(filePath) {
|
|
@@ -5,6 +5,19 @@ export declare function transformWorkflowDirectives(input: {
|
|
|
5
5
|
mode: WorkflowDirectiveMode;
|
|
6
6
|
moduleSpecifier: string | undefined;
|
|
7
7
|
source: string;
|
|
8
|
+
/**
|
|
9
|
+
* Package-qualified module specifier without the `@<pkg.version>`
|
|
10
|
+
* stamp. Used to mint workflow ids for functions named in
|
|
11
|
+
* {@link transformWorkflowDirectives.input.stableWorkflowNames} so
|
|
12
|
+
* the bundled id matches the runtime reference on every deployment.
|
|
13
|
+
*/
|
|
14
|
+
stableModuleSpecifier?: string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Workflow function names whose bundled id should be emitted without
|
|
17
|
+
* the package version stamp. See `STABLE_WORKFLOW_NAMES` in
|
|
18
|
+
* `workflow-runtime.ts` for the canonical set ash itself uses.
|
|
19
|
+
*/
|
|
20
|
+
stableWorkflowNames?: ReadonlySet<string>;
|
|
8
21
|
}): Promise<{
|
|
9
22
|
code: string;
|
|
10
23
|
workflowManifest: WorkflowManifest;
|
|
@@ -13,14 +13,19 @@ export async function transformWorkflowDirectives(input) {
|
|
|
13
13
|
if (functions.length === 0) {
|
|
14
14
|
return { code: input.source, workflowManifest: {} };
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
// Step ids stay version-stamped — they are per-deployment internal
|
|
17
|
+
// identifiers, not cross-deployment routing keys. Only workflow
|
|
18
|
+
// functions whose name appears in `stableWorkflowNames` opt out of
|
|
19
|
+
// the version stamp.
|
|
20
|
+
const defaultIdBase = input.moduleSpecifier ?? `./${stripJavaScriptExtension(input.filename)}`;
|
|
21
|
+
const stableIdBase = input.stableModuleSpecifier ?? defaultIdBase;
|
|
17
22
|
const manifest = {};
|
|
18
23
|
const replacements = [];
|
|
19
24
|
const suffixes = [];
|
|
20
25
|
let hasStepRegistration = false;
|
|
21
26
|
for (const fn of functions) {
|
|
22
27
|
if (fn.directive === "use step") {
|
|
23
|
-
const stepId = createStepId(
|
|
28
|
+
const stepId = createStepId(defaultIdBase, fn.name);
|
|
24
29
|
manifest.steps ??= {};
|
|
25
30
|
const stepsForFile = (manifest.steps[input.filename] ??= {});
|
|
26
31
|
stepsForFile[fn.name] = { stepId };
|
|
@@ -44,7 +49,8 @@ export async function transformWorkflowDirectives(input) {
|
|
|
44
49
|
}
|
|
45
50
|
continue;
|
|
46
51
|
}
|
|
47
|
-
const
|
|
52
|
+
const isStable = input.stableWorkflowNames?.has(fn.name) === true;
|
|
53
|
+
const workflowId = `workflow//${isStable ? stableIdBase : defaultIdBase}//${fn.name}`;
|
|
48
54
|
manifest.workflows ??= {};
|
|
49
55
|
const workflowsForFile = (manifest.workflows[input.filename] ??= {});
|
|
50
56
|
workflowsForFile[fn.name] = { workflowId };
|
|
@@ -66,7 +72,7 @@ export async function transformWorkflowDirectives(input) {
|
|
|
66
72
|
const hasWorkflowDirective = functions.some((fn) => fn.directive === "use workflow");
|
|
67
73
|
if (input.mode === "workflow" && !hasWorkflowDirective) {
|
|
68
74
|
return {
|
|
69
|
-
code: `${manifestComment}\n${createWorkflowStepProxySource(input.source, ast, functions,
|
|
75
|
+
code: `${manifestComment}\n${createWorkflowStepProxySource(input.source, ast, functions, defaultIdBase)}`,
|
|
70
76
|
workflowManifest: manifest,
|
|
71
77
|
};
|
|
72
78
|
}
|
|
@@ -76,20 +76,25 @@ export interface RuntimeIdentity {
|
|
|
76
76
|
* `message` is either a plain text string or an AI SDK `UserContent`
|
|
77
77
|
* array (mixing `text`, `image`, and `file` parts). Clients pass
|
|
78
78
|
* multimodal attachments with the same shape AI SDK's `useChat`
|
|
79
|
-
* `sendMessage({ files })` produces.
|
|
79
|
+
* `sendMessage({ files })` produces. `clientContext` is one-turn
|
|
80
|
+
* client/page context; the channel converts it into internal model context.
|
|
80
81
|
*/
|
|
81
82
|
export type HandleMessageRequestBody = {
|
|
82
83
|
readonly message: string | UserContent;
|
|
84
|
+
readonly clientContext?: string | readonly string[] | JsonObject;
|
|
83
85
|
} | {
|
|
84
86
|
readonly continuationToken: string;
|
|
85
87
|
readonly message: string | UserContent;
|
|
88
|
+
readonly clientContext?: string | readonly string[] | JsonObject;
|
|
86
89
|
} | {
|
|
87
90
|
readonly continuationToken: string;
|
|
88
91
|
readonly inputResponses: readonly InputResponse[];
|
|
92
|
+
readonly clientContext?: string | readonly string[] | JsonObject;
|
|
89
93
|
} | {
|
|
90
94
|
readonly continuationToken: string;
|
|
91
95
|
readonly inputResponses: readonly InputResponse[];
|
|
92
96
|
readonly message: string | UserContent;
|
|
97
|
+
readonly clientContext?: string | readonly string[] | JsonObject;
|
|
93
98
|
};
|
|
94
99
|
/**
|
|
95
100
|
* JSON response returned when the message route accepts a start or resume
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import {} from "ai";
|
|
1
2
|
import { ASH_MESSAGE_STREAM_CONTENT_TYPE, ASH_MESSAGE_STREAM_FORMAT, ASH_MESSAGE_STREAM_VERSION, ASH_SESSION_ID_HEADER, ASH_STREAM_FORMAT_HEADER, ASH_STREAM_VERSION_HEADER, } from "#protocol/message.js";
|
|
2
3
|
import { isInputResponse } from "#runtime/input/types.js";
|
|
3
4
|
import { createUnauthorizedResponse } from "#public/channels/auth.js";
|
|
4
5
|
import { collectUploadPolicyViolations, formatUploadPolicyViolation, mergeUploadPolicy, } from "#public/channels/upload-policy.js";
|
|
5
6
|
import { defineChannel, POST, GET } from "#public/definitions/defineChannel.js";
|
|
7
|
+
import { parseJsonObject } from "#shared/json.js";
|
|
6
8
|
export function ashChannel(input) {
|
|
7
9
|
const uploadPolicy = mergeUploadPolicy(input.uploadPolicy);
|
|
8
10
|
return defineChannel({
|
|
@@ -29,7 +31,7 @@ export function ashChannel(input) {
|
|
|
29
31
|
if (policyRejection !== null)
|
|
30
32
|
return policyRejection;
|
|
31
33
|
const token = `ash:${crypto.randomUUID()}`;
|
|
32
|
-
const session = await send(body
|
|
34
|
+
const session = await send(createSendPayload(body), {
|
|
33
35
|
auth: sessionAuth,
|
|
34
36
|
continuationToken: token,
|
|
35
37
|
});
|
|
@@ -79,6 +81,7 @@ export function ashChannel(input) {
|
|
|
79
81
|
const session = await send({
|
|
80
82
|
inputResponses: body.inputResponses,
|
|
81
83
|
message: body.message,
|
|
84
|
+
modelContext: body.modelContext,
|
|
82
85
|
}, {
|
|
83
86
|
auth: sessionAuth,
|
|
84
87
|
continuationToken: body.continuationToken,
|
|
@@ -137,10 +140,13 @@ function parseCreateBody(payload) {
|
|
|
137
140
|
const message = parseMessageField(payload.message);
|
|
138
141
|
if (message instanceof Response)
|
|
139
142
|
return message;
|
|
143
|
+
const modelContext = parseClientContextField(payload.clientContext);
|
|
144
|
+
if (modelContext instanceof Response)
|
|
145
|
+
return modelContext;
|
|
140
146
|
if (message === undefined) {
|
|
141
147
|
return Response.json({ error: "Missing or empty 'message' field.", ok: false }, { status: 400 });
|
|
142
148
|
}
|
|
143
|
-
return { message };
|
|
149
|
+
return { message, modelContext };
|
|
144
150
|
}
|
|
145
151
|
function parseContinueBody(payload) {
|
|
146
152
|
const continuationToken = typeof payload.continuationToken === "string" && payload.continuationToken.length > 0
|
|
@@ -155,13 +161,22 @@ function parseContinueBody(payload) {
|
|
|
155
161
|
const inputResponses = parseInputResponses(payload.inputResponses);
|
|
156
162
|
if (inputResponses instanceof Response)
|
|
157
163
|
return inputResponses;
|
|
164
|
+
const modelContext = parseClientContextField(payload.clientContext);
|
|
165
|
+
if (modelContext instanceof Response)
|
|
166
|
+
return modelContext;
|
|
158
167
|
if (message === undefined && inputResponses === undefined) {
|
|
159
168
|
return Response.json({
|
|
160
169
|
error: "Expected a non-empty 'message', a non-empty 'inputResponses' array, or both.",
|
|
161
170
|
ok: false,
|
|
162
171
|
}, { status: 400 });
|
|
163
172
|
}
|
|
164
|
-
return { message, continuationToken, inputResponses };
|
|
173
|
+
return { message, continuationToken, inputResponses, modelContext };
|
|
174
|
+
}
|
|
175
|
+
function createSendPayload(body) {
|
|
176
|
+
if (body.modelContext === undefined) {
|
|
177
|
+
return body.message;
|
|
178
|
+
}
|
|
179
|
+
return { message: body.message, modelContext: body.modelContext };
|
|
165
180
|
}
|
|
166
181
|
function parseMessageField(value) {
|
|
167
182
|
if (value === undefined)
|
|
@@ -255,6 +270,38 @@ function parseInputResponses(value) {
|
|
|
255
270
|
}
|
|
256
271
|
return inputResponses;
|
|
257
272
|
}
|
|
273
|
+
const CLIENT_CONTEXT_PREFIX = "Ephemeral client context:\n";
|
|
274
|
+
function parseClientContextField(value) {
|
|
275
|
+
if (value === undefined)
|
|
276
|
+
return undefined;
|
|
277
|
+
if (typeof value === "string") {
|
|
278
|
+
return value.length > 0 ? [toClientContextMessage(value)] : undefined;
|
|
279
|
+
}
|
|
280
|
+
if (Array.isArray(value)) {
|
|
281
|
+
if (value.length === 0)
|
|
282
|
+
return undefined;
|
|
283
|
+
if (!value.every((entry) => typeof entry === "string" && entry.length > 0)) {
|
|
284
|
+
return Response.json({ error: "Expected 'clientContext' array entries to be non-empty strings.", ok: false }, { status: 400 });
|
|
285
|
+
}
|
|
286
|
+
return value.map((entry) => toClientContextMessage(entry));
|
|
287
|
+
}
|
|
288
|
+
if (value === null || typeof value !== "object") {
|
|
289
|
+
return Response.json({
|
|
290
|
+
error: "Expected 'clientContext' to be a string, string array, or JSON object.",
|
|
291
|
+
ok: false,
|
|
292
|
+
}, { status: 400 });
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
const json = parseJsonObject(value);
|
|
296
|
+
return [toClientContextMessage(JSON.stringify(json))];
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
return Response.json({ error: "Expected 'clientContext' to be a JSON-serializable object.", ok: false }, { status: 400 });
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
function toClientContextMessage(content) {
|
|
303
|
+
return { role: "user", content: `${CLIENT_CONTEXT_PREFIX}${content}` };
|
|
304
|
+
}
|
|
258
305
|
function parseStartIndex(request) {
|
|
259
306
|
const raw = new URL(request.url).searchParams.get("startIndex");
|
|
260
307
|
if (raw === null)
|
|
@@ -2,15 +2,12 @@
|
|
|
2
2
|
* Runtime context helpers for authored code.
|
|
3
3
|
*
|
|
4
4
|
* These APIs work only inside active authored runtime execution such as
|
|
5
|
-
* tools and other Ash-invoked callbacks.
|
|
6
|
-
* `AshContext` container bound via `AsyncLocalStorage`.
|
|
5
|
+
* tools and other Ash-invoked callbacks.
|
|
7
6
|
*
|
|
8
7
|
* @example
|
|
9
8
|
* ```ts
|
|
10
|
-
* import {
|
|
9
|
+
* import { defineState, getSession } from "experimental-ash/context";
|
|
11
10
|
* ```
|
|
12
11
|
*/
|
|
13
|
-
export {
|
|
14
|
-
export type
|
|
15
|
-
export { type ContextAccessor, ContextKey, type ContextKeyOptions } from "#context/key.js";
|
|
16
|
-
export type { ContextProvider, ContextReader } from "#context/provider.js";
|
|
12
|
+
export { getSession, type Session, type SessionAuth, type SessionAuthContext, type SessionParent, type SessionTurn, } from "#context/accessors.js";
|
|
13
|
+
export { defineState, type StateHandle } from "#public/definitions/state.js";
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
* Runtime context helpers for authored code.
|
|
3
3
|
*
|
|
4
4
|
* These APIs work only inside active authored runtime execution such as
|
|
5
|
-
* tools and other Ash-invoked callbacks.
|
|
6
|
-
* `AshContext` container bound via `AsyncLocalStorage`.
|
|
5
|
+
* tools and other Ash-invoked callbacks.
|
|
7
6
|
*
|
|
8
7
|
* @example
|
|
9
8
|
* ```ts
|
|
10
|
-
* import {
|
|
9
|
+
* import { defineState, getSession } from "experimental-ash/context";
|
|
11
10
|
* ```
|
|
12
11
|
*/
|
|
13
|
-
export {
|
|
14
|
-
export {
|
|
12
|
+
export { getSession, } from "#context/accessors.js";
|
|
13
|
+
export { defineState } from "#public/definitions/state.js";
|