@noodleseed/one 0.151.1 → 0.152.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/dist/assistant-embed-scaffold-template.d.ts +1 -0
- package/dist/assistant-embed-scaffold-template.d.ts.map +1 -1
- package/dist/assistant-embed-scaffold-template.js +80 -12
- package/dist/assistant-embed-scaffold-template.js.map +1 -1
- package/dist/commands/assistant-embed-ops.d.ts.map +1 -1
- package/dist/commands/assistant-embed-ops.js +141 -4
- package/dist/commands/assistant-embed-ops.js.map +1 -1
- package/dist/commands/assistant-ops.js +1 -1
- package/dist/commands/assistant-ops.js.map +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/behavior-skills.js +10 -10
- package/node_modules/@noodle-borg/agent-kit/dist/generated/example-files.js +6 -5
- package/node_modules/@noodle-borg/agent-kit/dist/index.js +13 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-authoring-refs.js +8 -0
- package/node_modules/@noodle-borg/agent-kit/dist/skill-content.js +1 -1
- package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-operations-ref.js +78 -0
- package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-ref.js +156 -135
- package/node_modules/@noodle-borg/agent-kit/dist/skill-embedded-assistant-renderer-ref.js +109 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-browser-fields.d.ts +3 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-browser-fields.js +15 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-configuration.d.ts +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-configuration.js +1 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-store.d.ts +19 -11
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-store.js +24 -23
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-transcript-events.d.ts +24 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-transcript-events.js +39 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-transcript.d.ts +6 -2
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-transcript.js +11 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-view-availability.d.ts +8 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/assistant-view-availability.js +8 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/elevation-store.d.ts +3 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/elevation.d.ts +7 -1
- package/node_modules/@noodle-borg/assistant-gateway/dist/elevation.js +1 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/in-memory-elevation-store.d.ts +1 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/in-memory-elevation-store.js +1 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/portable.d.ts +1 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/portable.js +1 -0
- package/node_modules/@noodle-borg/assistant-gateway/package.json +1 -0
- package/node_modules/@noodle-borg/authoring/dist/server.d.ts +2 -0
- package/node_modules/@noodle-borg/authoring/dist/server.js +3 -0
- package/node_modules/@noodle-borg/compiler/dist/artifact/types.d.ts +1 -0
- package/node_modules/@noodle-borg/compiler/dist/artifact/version.d.ts +4 -1
- package/node_modules/@noodle-borg/compiler/dist/artifact/version.js +4 -1
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +4 -0
- package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +20 -1
- package/node_modules/@noodle-borg/compiler/dist/state-handles.js +1 -0
- package/node_modules/@noodle-borg/runtime/dist/index.d.ts +1 -0
- package/node_modules/@noodle-borg/runtime/dist/index.js +1 -0
- package/node_modules/@noodle-borg/runtime/dist/state-handle-ownership.d.ts +21 -0
- package/node_modules/@noodle-borg/runtime/dist/state-handle-ownership.js +10 -0
- package/node_modules/@noodle-borg/runtime/package.json +6 -1
- package/node_modules/@noodle-borg/service/dist/routes/assistant-agent.js +7 -2
- package/node_modules/@noodle-borg/service/dist/routes/assistant-elevation.js +14 -7
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interaction-replay.js +4 -2
- package/node_modules/@noodle-borg/service/dist/routes/assistant-interactions.js +4 -2
- package/node_modules/@noodle-borg/service/dist/routes/assistant-transcript.js +48 -9
- package/node_modules/@noodle-borg/service/dist/service.js +3 -0
- package/node_modules/@noodle-borg/wire-contracts/dist/assistant.d.ts +19 -25
- package/node_modules/@noodle-borg/wire-contracts/dist/assistant.js +20 -34
- package/node_modules/@noodleseed/assistant/README.md +1 -1
- package/package.json +1 -1
|
@@ -490,8 +490,27 @@ const stateHandleSchema = z
|
|
|
490
490
|
.positive()
|
|
491
491
|
.max(60 * 60 * 24 * 30)
|
|
492
492
|
.optional(),
|
|
493
|
+
claimOnAuthentication: z.literal(true).optional(),
|
|
493
494
|
})
|
|
494
|
-
.strict()
|
|
495
|
+
.strict()
|
|
496
|
+
.superRefine((handle, ctx) => {
|
|
497
|
+
if (handle.claimOnAuthentication !== true)
|
|
498
|
+
return;
|
|
499
|
+
if (handle.scope !== 'caller') {
|
|
500
|
+
ctx.addIssue({
|
|
501
|
+
code: 'custom',
|
|
502
|
+
path: ['scope'],
|
|
503
|
+
message: 'claimOnAuthentication requires an explicit caller scope',
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
if (handle.ttlSeconds === undefined) {
|
|
507
|
+
ctx.addIssue({
|
|
508
|
+
code: 'custom',
|
|
509
|
+
path: ['ttlSeconds'],
|
|
510
|
+
message: 'claimOnAuthentication requires a finite ttlSeconds',
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
});
|
|
495
514
|
const stateSchema = z
|
|
496
515
|
.object({
|
|
497
516
|
handles: z
|
|
@@ -27,6 +27,7 @@ export function compileState(manifest, schemasMap, errors) {
|
|
|
27
27
|
version: handle.version,
|
|
28
28
|
scope: handle.scope ?? 'deployment',
|
|
29
29
|
...(handle.ttlSeconds !== undefined ? { ttlSeconds: handle.ttlSeconds } : {}),
|
|
30
|
+
...(handle.claimOnAuthentication === true ? { claimOnAuthentication: true } : {}),
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
33
|
return { handles };
|
|
@@ -18,6 +18,7 @@ export { AllowAllPolicy } from './policy/allow-all.js';
|
|
|
18
18
|
export type { PolicyContext, PolicyDecision, PolicyGate } from './policy/types.js';
|
|
19
19
|
export { type ConfirmationActionReview, type ConfirmationPreparationResult, type ConfirmationReview, type ConnectorFailureAttribution, type ElicitationRequest, type ElicitationResponse, type ExecutionError, type ExecutionErrorCode, type ExecutionResult, type InteractiveExecutionResult, isConfirmationRequired, isInputRequired, isInputRequiredForConfirmation, type PreparedOperationAction, type PreparedToolContinuation, type ToolContinuation, type ToolPreparationContinuation, } from './result.js';
|
|
20
20
|
export { splitResultMeta } from './result-meta.js';
|
|
21
|
+
export { type CallerStateAdoptionInput, type CallerStateAdoptionResult, claimableStateHandleNames, } from './state-handle-ownership.js';
|
|
21
22
|
export { assertExpectedStateRevision, assertNoSecretValue, assertSchemaValue, assertStateHandleNotCompleted, COMPLETE_STATE_OPERATION, createMutableStateHandleRecord, createStateConnector, InMemoryStateHandleStore, type MutableStateHandleRecord, PATCH_STATE_OPERATION, READ_STATE_OPERATION, STATE_CONNECTOR_ID, STATE_CONNECTOR_VERSION, STATE_OPERATION_SIGNATURES, StateConnector, type StateHandleRecord, type StateHandleStore, type StateInput, type StateMutationInput, type StatePatchInput, stateHandleRecordForMutation, toPublicStateHandleRecord, } from './state-handles.js';
|
|
22
23
|
export type { ToolDispatchContext, ToolDispatchDecision, ToolDispatchHook, } from './tool-dispatch.js';
|
|
23
24
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -15,5 +15,6 @@ export { resolveManagedOrigins, } from './managed-origins.js';
|
|
|
15
15
|
export { AllowAllPolicy } from './policy/allow-all.js';
|
|
16
16
|
export { isConfirmationRequired, isInputRequired, isInputRequiredForConfirmation, } from './result.js';
|
|
17
17
|
export { splitResultMeta } from './result-meta.js';
|
|
18
|
+
export { claimableStateHandleNames, } from './state-handle-ownership.js';
|
|
18
19
|
export { assertExpectedStateRevision, assertNoSecretValue, assertSchemaValue, assertStateHandleNotCompleted, COMPLETE_STATE_OPERATION, createMutableStateHandleRecord, createStateConnector, InMemoryStateHandleStore, PATCH_STATE_OPERATION, READ_STATE_OPERATION, STATE_CONNECTOR_ID, STATE_CONNECTOR_VERSION, STATE_OPERATION_SIGNATURES, StateConnector, stateHandleRecordForMutation, toPublicStateHandleRecord, } from './state-handles.js';
|
|
19
20
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ArtifactState } from '@noodle-borg/compiler';
|
|
2
|
+
export interface CallerStateAdoptionInput {
|
|
3
|
+
readonly deploymentId: string;
|
|
4
|
+
readonly handles: readonly string[];
|
|
5
|
+
readonly sourceCallerSubject: string;
|
|
6
|
+
readonly targetCallerSubject: string;
|
|
7
|
+
/** The old anonymous session's absolute expiry; redirects never extend its authority. */
|
|
8
|
+
readonly redirectExpiresAt: Date;
|
|
9
|
+
readonly now: Date;
|
|
10
|
+
}
|
|
11
|
+
export type CallerStateAdoptionResult = {
|
|
12
|
+
readonly ok: true;
|
|
13
|
+
readonly adoptedHandles: readonly string[];
|
|
14
|
+
readonly adoptedRecords: number;
|
|
15
|
+
} | {
|
|
16
|
+
readonly ok: false;
|
|
17
|
+
readonly reason: 'state_key_conflict';
|
|
18
|
+
};
|
|
19
|
+
/** The canonical sorted declaration projection stored on an elevation ticket. */
|
|
20
|
+
export declare function claimableStateHandleNames(state: ArtifactState | undefined): readonly string[];
|
|
21
|
+
//# sourceMappingURL=state-handle-ownership.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** The canonical sorted declaration projection stored on an elevation ticket. */
|
|
2
|
+
export function claimableStateHandleNames(state) {
|
|
3
|
+
if (state === undefined)
|
|
4
|
+
return [];
|
|
5
|
+
return Object.entries(state.handles)
|
|
6
|
+
.filter(([, handle]) => handle.claimOnAuthentication === true)
|
|
7
|
+
.map(([name]) => name)
|
|
8
|
+
.sort();
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=state-handle-ownership.js.map
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
".": {
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./postgres": {
|
|
17
|
+
"types": "./dist/postgres.d.ts",
|
|
18
|
+
"import": "./dist/postgres.js"
|
|
15
19
|
}
|
|
16
20
|
},
|
|
17
21
|
"files": [
|
|
@@ -26,6 +30,7 @@
|
|
|
26
30
|
"@noodle-borg/module": "0.0.0"
|
|
27
31
|
},
|
|
28
32
|
"devDependencies": {
|
|
29
|
-
"@types/node": "^24.13.1"
|
|
33
|
+
"@types/node": "^24.13.1",
|
|
34
|
+
"@types/pg": "^8.20.0"
|
|
30
35
|
}
|
|
31
36
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ADMISSION_DEFAULTS } from '@noodle-borg/admission-limits/portable';
|
|
2
2
|
import { assistantCoreModelMessages, assistantTurnModelContextMessages, requestAssistantSuggestedPrompts, requestModelCompletion, resolveAssistantContextProviderModelResult, } from '@noodle-borg/assistant-gateway/model-runtime';
|
|
3
|
-
import { assistantGuideModelContext, assistantModelToolOncePerSession, assistantModelToolRequiredWhenVisible, assistantOmittedToolResult, assistantViewAvailableData, dispatchAssistantTool, projectAssistantGuide, publicSurfaceOf, remainingTurnTokens, selectAssistantModelTools, toolTouchesDelegatedAuth, withAssistantSessionExecutionAuthority, } from '@noodle-borg/assistant-gateway/portable';
|
|
3
|
+
import { assistantGuideModelContext, assistantModelToolOncePerSession, assistantModelToolRequiredWhenVisible, assistantOmittedToolResult, assistantViewAvailableData, dispatchAssistantTool, projectAssistantGuide, publicSurfaceOf, recoverableAssistantView, remainingTurnTokens, selectAssistantModelTools, toolTouchesDelegatedAuth, withAssistantSessionExecutionAuthority, } from '@noodle-borg/assistant-gateway/portable';
|
|
4
4
|
import { validateJsonSchemaWithDefaults } from '@noodle-borg/compiler';
|
|
5
5
|
import { guardedFetch } from '@noodle-borg/connector-http';
|
|
6
6
|
import { evaluateToolAuthorization } from '@noodle-borg/protocol';
|
|
@@ -207,6 +207,9 @@ export async function runAgentTurn(target, session, message, context, deps, emit
|
|
|
207
207
|
tool,
|
|
208
208
|
session,
|
|
209
209
|
assistant,
|
|
210
|
+
...(target.served.artifact.server.state === undefined
|
|
211
|
+
? {}
|
|
212
|
+
: { state: target.served.artifact.server.state }),
|
|
210
213
|
elevations: deps.elevations,
|
|
211
214
|
...(delegatedKeys !== undefined && delegatedKeys.size > 0
|
|
212
215
|
? {
|
|
@@ -269,8 +272,10 @@ export async function runAgentTurn(target, session, message, context, deps, emit
|
|
|
269
272
|
result: dispatch.output,
|
|
270
273
|
arguments: args,
|
|
271
274
|
}, (failure) => deps.logger?.warn('assistant.view.unresolved', { ...failure }));
|
|
272
|
-
if (view)
|
|
275
|
+
if (view) {
|
|
276
|
+
await deps.store.replaceLatestView(session.id, recoverableAssistantView(view));
|
|
273
277
|
emit({ event: 'view_available', data: { ...view } });
|
|
278
|
+
}
|
|
274
279
|
messages.push({
|
|
275
280
|
role: 'tool',
|
|
276
281
|
tool_call_id: call.id,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { completeElevation, publicSurfaceOf } from '@noodle-borg/assistant-gateway/portable';
|
|
2
2
|
import { anonymousBehavior } from '@noodle-borg/compiler';
|
|
3
|
+
import { claimableStateHandleNames } from '@noodle-borg/runtime';
|
|
3
4
|
import { assistantSessionResponseSchema } from '@noodle-borg/wire-contracts';
|
|
4
5
|
import { sendJson } from '../http-util.js';
|
|
5
6
|
function isMixed(surface) {
|
|
@@ -16,6 +17,7 @@ const ELEVATION_REFUSAL_MESSAGES = {
|
|
|
16
17
|
elevation_tenant_mismatch: 'sign-in ticket belongs to a different tenant',
|
|
17
18
|
elevation_session_unavailable: 'the conversation behind this sign-in is no longer available',
|
|
18
19
|
elevation_already_signed_in: 'this conversation is already signed in',
|
|
20
|
+
elevation_state_conflict: 'the signed-in account already has state at the same key; restart or resolve that draft first',
|
|
19
21
|
};
|
|
20
22
|
/**
|
|
21
23
|
* Decide whether this call is an elevation instead of an execution.
|
|
@@ -40,6 +42,7 @@ export async function interceptForElevation(input) {
|
|
|
40
42
|
sessionId: input.session.id,
|
|
41
43
|
tenant: input.session.tenant,
|
|
42
44
|
tool: input.tool.name,
|
|
45
|
+
claimableStateHandles: claimableStateHandleNames(input.state),
|
|
43
46
|
now: input.now,
|
|
44
47
|
});
|
|
45
48
|
return {
|
|
@@ -84,7 +87,7 @@ export async function elevateAssistantSession(res, deps, input) {
|
|
|
84
87
|
code: 'elevation_unavailable',
|
|
85
88
|
});
|
|
86
89
|
}
|
|
87
|
-
const
|
|
90
|
+
const request = {
|
|
88
91
|
continuation: input.signInTicket,
|
|
89
92
|
tenant: input.client.tenant,
|
|
90
93
|
caller: input.caller,
|
|
@@ -95,11 +98,14 @@ export async function elevateAssistantSession(res, deps, input) {
|
|
|
95
98
|
...(input.customerRouting ? { customerRouting: input.customerRouting } : {}),
|
|
96
99
|
...(input.boundSurface ? { boundSurface: input.boundSurface } : {}),
|
|
97
100
|
resume: input.resume,
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
};
|
|
102
|
+
const elevated = deps.elevationCoordinator
|
|
103
|
+
? await deps.elevationCoordinator.complete(request)
|
|
104
|
+
: await completeElevation(request, {
|
|
105
|
+
elevations: deps.elevations,
|
|
106
|
+
elevateSession: (elevation) => deps.store.elevateSession(elevation),
|
|
107
|
+
now: () => deps.clock?.() ?? new Date(),
|
|
108
|
+
});
|
|
103
109
|
if (!elevated.ok) {
|
|
104
110
|
await deps.audit.emit({
|
|
105
111
|
eventType: 'assistant.session.elevation_refused',
|
|
@@ -137,7 +143,8 @@ export async function elevateAssistantSession(res, deps, input) {
|
|
|
137
143
|
endpoints: input.endpoints,
|
|
138
144
|
...(input.configuration ? { configuration: input.configuration } : {}),
|
|
139
145
|
// The armed hint: the widget answers with one { resume: true } turn on the turns endpoint.
|
|
140
|
-
...(
|
|
146
|
+
...(elevated.resumeArmed ? { resume: { tool: elevated.tool } } : {}),
|
|
147
|
+
continuedAfterAuthentication: true,
|
|
141
148
|
};
|
|
142
149
|
assistantSessionResponseSchema.parse(body);
|
|
143
150
|
return sendJson(res, 200, body);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assistantInteractionTool, assistantViewAvailableData, auditAssistantInteraction, } from '@noodle-borg/assistant-gateway/portable';
|
|
1
|
+
import { assistantInteractionTool, assistantViewAvailableData, auditAssistantInteraction, recoverableAssistantView, } from '@noodle-borg/assistant-gateway/portable';
|
|
2
2
|
import { sendJson } from '../http-util.js';
|
|
3
3
|
import { now } from './assistant.js';
|
|
4
4
|
import { assistantInteractionScope } from './assistant-interaction-resolution.js';
|
|
@@ -71,8 +71,10 @@ export async function replayOrConflict(res, deps, session, interaction, action)
|
|
|
71
71
|
replayed: true,
|
|
72
72
|
}, (failure) => deps.logger?.warn('assistant.view.unresolved', { ...failure }))
|
|
73
73
|
: undefined;
|
|
74
|
-
if (view)
|
|
74
|
+
if (view) {
|
|
75
|
+
await deps.store.replaceLatestView(session.id, recoverableAssistantView(view));
|
|
75
76
|
writeViewAvailable(res, view);
|
|
77
|
+
}
|
|
76
78
|
}
|
|
77
79
|
else if (current.status === 'failed') {
|
|
78
80
|
writeInteractionError(res, current.publicOutcome.code, false);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AssistantInteractionCapacityError, assistantConfirmationReview, assistantConfirmationTransition, assistantInputTransition, assistantInteractionTool, assistantPreparedArgumentReview, assistantPreparedToolContinuation, assistantSafeOutput, assistantToolContinuation, assistantViewAvailableData, auditAssistantInteraction, withAssistantSessionExecutionAuthority, } from '@noodle-borg/assistant-gateway/portable';
|
|
1
|
+
import { AssistantInteractionCapacityError, assistantConfirmationReview, assistantConfirmationTransition, assistantInputTransition, assistantInteractionTool, assistantPreparedArgumentReview, assistantPreparedToolContinuation, assistantSafeOutput, assistantToolContinuation, assistantViewAvailableData, auditAssistantInteraction, recoverableAssistantView, withAssistantSessionExecutionAuthority, } from '@noodle-borg/assistant-gateway/portable';
|
|
2
2
|
import { executePreparedTool, executeToolInteractive, resumeTool, resumeToolPreparation, } from '@noodle-borg/runtime';
|
|
3
3
|
import { readJsonBody, sendJson } from '../http-util.js';
|
|
4
4
|
import { applyBrowserCors, authenticateSession, now, } from './assistant.js';
|
|
@@ -364,8 +364,10 @@ async function finishExecution(res, deps, session, interaction, context, result,
|
|
|
364
364
|
tool: toolName,
|
|
365
365
|
result: safeOutput,
|
|
366
366
|
}, (failure) => deps.logger?.warn('assistant.view.unresolved', { ...failure }));
|
|
367
|
-
if (view)
|
|
367
|
+
if (view) {
|
|
368
|
+
await deps.store.replaceLatestView(session.id, recoverableAssistantView(view));
|
|
368
369
|
writeViewAvailable(res, view);
|
|
370
|
+
}
|
|
369
371
|
await narrateResolvedInteraction(res, deps, target, session, toolName, 'accept', safeOutput, context, suggestions);
|
|
370
372
|
return endInteractionSse(res);
|
|
371
373
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { visibleTranscript } from '@noodle-borg/assistant-gateway/portable';
|
|
2
|
-
import {
|
|
3
|
-
import { sendJson } from '../http-util.js';
|
|
1
|
+
import { assistantConfirmationProposal, assistantTranscriptEvents, assistantViewAvailableData, visibleTranscript, } from '@noodle-borg/assistant-gateway/portable';
|
|
2
|
+
import { assistantWireEventSchema } from '@noodle-borg/wire-contracts';
|
|
4
3
|
import { applyBrowserCors, authenticateSession } from './assistant-route-http.js';
|
|
4
|
+
import { sessionScopedTarget } from './assistant-session-target.js';
|
|
5
5
|
/**
|
|
6
6
|
* The bounded visible-transcript read (ADR 0141/0201 amendments 2026-08-26), in its own module for
|
|
7
7
|
* the same reason `assistant-elevation.ts` is: `assistant.ts` is at its size limit, and this is a
|
|
@@ -18,15 +18,54 @@ export async function handleAssistantTranscript(req, res, deps) {
|
|
|
18
18
|
if (!session)
|
|
19
19
|
return;
|
|
20
20
|
applyBrowserCors(req, res, session.origin);
|
|
21
|
-
const
|
|
21
|
+
const target = await sessionScopedTarget(deps.registry, session);
|
|
22
|
+
const latestView = target && session.latestView
|
|
23
|
+
? assistantViewAvailableData(target.served.artifact, { ...session.latestView, replayed: true }, (failure) => deps.logger?.warn('assistant.view.unresolved', { ...failure }))
|
|
24
|
+
: undefined;
|
|
25
|
+
const pending = await deps.store.findPendingInteraction({
|
|
26
|
+
sessionId: session.id,
|
|
27
|
+
deploymentId: session.deploymentId,
|
|
28
|
+
now: deps.clock?.() ?? new Date(),
|
|
29
|
+
});
|
|
30
|
+
const pendingInteraction = target && pending && target.served.artifact.tools.some((tool) => tool.name === pending.tool)
|
|
31
|
+
? pending.kind === 'confirmation'
|
|
32
|
+
? {
|
|
33
|
+
event: 'tool_proposed',
|
|
34
|
+
data: {
|
|
35
|
+
id: pending.id,
|
|
36
|
+
tool: pending.tool,
|
|
37
|
+
...assistantConfirmationProposal(pending.review),
|
|
38
|
+
expiresAt: pending.expiresAt,
|
|
39
|
+
requiresConfirmation: true,
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
: {
|
|
43
|
+
event: 'input_requested',
|
|
44
|
+
data: {
|
|
45
|
+
id: pending.id,
|
|
46
|
+
message: pending.message,
|
|
47
|
+
requestedSchema: pending.requestedSchema,
|
|
48
|
+
expiresAt: pending.expiresAt,
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
: undefined;
|
|
52
|
+
const events = assistantTranscriptEvents({
|
|
22
53
|
entries: visibleTranscript(session.history),
|
|
23
54
|
...(session.latestSuggestions?.phase === 'follow_up'
|
|
24
55
|
? { suggestions: session.latestSuggestions }
|
|
25
56
|
: {}),
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
57
|
+
...(latestView === undefined ? {} : { latestView }),
|
|
58
|
+
...(pendingInteraction === undefined ? {} : { pendingInteraction }),
|
|
59
|
+
});
|
|
60
|
+
res.writeHead(200, {
|
|
61
|
+
'content-type': 'text/event-stream; charset=utf-8',
|
|
62
|
+
'cache-control': 'no-store',
|
|
63
|
+
});
|
|
64
|
+
for (const event of events) {
|
|
65
|
+
// Parse before sending, like every assistant stream: contract drift fails at the service seam.
|
|
66
|
+
assistantWireEventSchema.parse(event);
|
|
67
|
+
res.write(`event: ${event.event}\ndata: ${JSON.stringify(event.data)}\n\n`);
|
|
68
|
+
}
|
|
69
|
+
res.end();
|
|
31
70
|
}
|
|
32
71
|
//# sourceMappingURL=assistant-transcript.js.map
|
|
@@ -241,6 +241,9 @@ export function createServiceHandler(registry, options = {}) {
|
|
|
241
241
|
appearance: assistantAppearance,
|
|
242
242
|
...(options.publicEmbeds !== undefined ? { publicEmbeds: options.publicEmbeds } : {}),
|
|
243
243
|
...(options.elevations !== undefined ? { elevations: options.elevations } : {}),
|
|
244
|
+
...(options.elevationCoordinator !== undefined
|
|
245
|
+
? { elevationCoordinator: options.elevationCoordinator }
|
|
246
|
+
: {}),
|
|
244
247
|
...(options.admissionCounters !== undefined
|
|
245
248
|
? { admissionCounters: options.admissionCounters }
|
|
246
249
|
: {}),
|
|
@@ -30,28 +30,9 @@ export declare const assistantSessionResponseSchema: z.ZodObject<{
|
|
|
30
30
|
resume: z.ZodOptional<z.ZodObject<{
|
|
31
31
|
tool: z.ZodString;
|
|
32
32
|
}, z.core.$strip>>;
|
|
33
|
+
continuedAfterAuthentication: z.ZodOptional<z.ZodLiteral<true>>;
|
|
33
34
|
}, z.core.$strip>;
|
|
34
35
|
export type AssistantSessionResponse = z.infer<typeof assistantSessionResponseSchema>;
|
|
35
|
-
/**
|
|
36
|
-
* The bounded visible transcript (ADR 0141/0201 amendments 2026-08-26): only rows that actually
|
|
37
|
-
* appeared in the panel — never tool internals, tickets, or model-facing scaffolding. Bounded by the
|
|
38
|
-
* session history window (40 messages); a read spends no turn budget. Strict, because the service
|
|
39
|
-
* parses its own response before sending, like the session exchange.
|
|
40
|
-
*/
|
|
41
|
-
export declare const assistantTranscriptResponseSchema: z.ZodObject<{
|
|
42
|
-
entries: z.ZodArray<z.ZodObject<{
|
|
43
|
-
role: z.ZodEnum<{
|
|
44
|
-
assistant: "assistant";
|
|
45
|
-
user: "user";
|
|
46
|
-
}>;
|
|
47
|
-
text: z.ZodString;
|
|
48
|
-
}, z.core.$strict>>;
|
|
49
|
-
suggestions: z.ZodOptional<z.ZodObject<{
|
|
50
|
-
phase: z.ZodLiteral<"follow_up">;
|
|
51
|
-
prompts: z.ZodArray<z.ZodString>;
|
|
52
|
-
}, z.core.$strict>>;
|
|
53
|
-
}, z.core.$strict>;
|
|
54
|
-
export type AssistantTranscriptResponse = z.infer<typeof assistantTranscriptResponseSchema>;
|
|
55
36
|
/** MCP-Apps-shaped, author-selected renderer summary included on one assistant turn. */
|
|
56
37
|
export declare const assistantModelContextUpdateSchema: z.ZodObject<{
|
|
57
38
|
content: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -150,6 +131,19 @@ export type AssistantInteractionRequest = z.infer<typeof assistantInteractionReq
|
|
|
150
131
|
* proposal/completion payloads while clients talking to older services tolerate absent new fields.
|
|
151
132
|
*/
|
|
152
133
|
export declare const assistantWireEventSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
134
|
+
event: z.ZodLiteral<string>;
|
|
135
|
+
data: z.ZodObject<{
|
|
136
|
+
message: z.ZodString;
|
|
137
|
+
}, z.core.$strip>;
|
|
138
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
139
|
+
event: z.ZodLiteral<string>;
|
|
140
|
+
data: z.ZodObject<{
|
|
141
|
+
tool: z.ZodString;
|
|
142
|
+
}, z.core.$strip>;
|
|
143
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
144
|
+
event: z.ZodLiteral<string>;
|
|
145
|
+
data: z.ZodObject<{}, z.core.$strip>;
|
|
146
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
153
147
|
event: z.ZodLiteral<string>;
|
|
154
148
|
data: z.ZodObject<{
|
|
155
149
|
turnId: z.ZodOptional<z.ZodString>;
|
|
@@ -210,18 +204,18 @@ export declare const assistantWireEventSchema: z.ZodUnion<readonly [z.ZodObject<
|
|
|
210
204
|
}, z.core.$strip>, z.ZodObject<{
|
|
211
205
|
event: z.ZodLiteral<string>;
|
|
212
206
|
data: z.ZodObject<{
|
|
213
|
-
turnId: z.ZodOptional<z.ZodString>;
|
|
214
|
-
id: z.ZodString;
|
|
215
207
|
tool: z.ZodString;
|
|
208
|
+
id: z.ZodString;
|
|
216
209
|
resourceUri: z.ZodString;
|
|
217
210
|
title: z.ZodOptional<z.ZodString>;
|
|
218
211
|
result: z.ZodJSONSchema;
|
|
219
212
|
arguments: z.ZodOptional<z.ZodJSONSchema>;
|
|
220
|
-
html: z.ZodOptional<z.ZodString>;
|
|
221
213
|
resourceMeta: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
222
214
|
allowedOpenDomains: z.ZodOptional<z.ZodArray<z.ZodURL>>;
|
|
215
|
+
turnId: z.ZodOptional<z.ZodString>;
|
|
216
|
+
html: z.ZodOptional<z.ZodString>;
|
|
223
217
|
replayed: z.ZodOptional<z.ZodLiteral<true>>;
|
|
224
|
-
}, z.core.$
|
|
218
|
+
}, z.core.$strict>;
|
|
225
219
|
}, z.core.$strip>, z.ZodObject<{
|
|
226
220
|
event: z.ZodLiteral<string>;
|
|
227
221
|
data: z.ZodObject<{
|
|
@@ -237,8 +231,8 @@ export declare const assistantWireEventSchema: z.ZodUnion<readonly [z.ZodObject<
|
|
|
237
231
|
data: z.ZodObject<{
|
|
238
232
|
turnId: z.ZodOptional<z.ZodString>;
|
|
239
233
|
phase: z.ZodEnum<{
|
|
240
|
-
follow_up: "follow_up";
|
|
241
234
|
initial: "initial";
|
|
235
|
+
follow_up: "follow_up";
|
|
242
236
|
}>;
|
|
243
237
|
prompts: z.ZodArray<z.ZodString>;
|
|
244
238
|
}, z.core.$strip>;
|
|
@@ -44,9 +44,9 @@ export const assistantSessionResponseSchema = z.object({
|
|
|
44
44
|
sandbox: z.url().optional(),
|
|
45
45
|
/**
|
|
46
46
|
* Additive bounded visible-transcript endpoint (ADR 0141/0201 amendments 2026-08-26): a
|
|
47
|
-
* session-token-authenticated POST
|
|
48
|
-
* navigation — the sign-in redirect above all. Absent on older services; the widget then
|
|
49
|
-
*
|
|
47
|
+
* session-token-authenticated POST replaying standard assistant events after a full-page
|
|
48
|
+
* navigation — the sign-in redirect above all. Absent on older services; the widget then starts
|
|
49
|
+
* visually fresh exactly as before.
|
|
50
50
|
*/
|
|
51
51
|
transcript: z.url().optional(),
|
|
52
52
|
/** Additive model-generated prompt suggestions; its presence is the client capability gate. */
|
|
@@ -59,30 +59,21 @@ export const assistantSessionResponseSchema = z.object({
|
|
|
59
59
|
* existing turns endpoint; older widgets strip unknown keys and simply never auto-resume.
|
|
60
60
|
*/
|
|
61
61
|
resume: z.object({ tool: z.string().min(1) }).optional(),
|
|
62
|
+
/** Additive elevation marker; the client renders one bounded continuation status. */
|
|
63
|
+
continuedAfterAuthentication: z.literal(true).optional(),
|
|
62
64
|
});
|
|
63
|
-
|
|
64
|
-
* The bounded visible transcript (ADR 0141/0201 amendments 2026-08-26): only rows that actually
|
|
65
|
-
* appeared in the panel — never tool internals, tickets, or model-facing scaffolding. Bounded by the
|
|
66
|
-
* session history window (40 messages); a read spends no turn budget. Strict, because the service
|
|
67
|
-
* parses its own response before sending, like the session exchange.
|
|
68
|
-
*/
|
|
69
|
-
export const assistantTranscriptResponseSchema = z
|
|
65
|
+
const recoverableViewSchema = z
|
|
70
66
|
.object({
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
phase: z.literal('follow_up'),
|
|
82
|
-
prompts: z.array(z.string().trim().min(1).max(240)).max(3),
|
|
83
|
-
})
|
|
84
|
-
.strict()
|
|
85
|
-
.optional(),
|
|
67
|
+
id: z.string().min(1),
|
|
68
|
+
tool: z.string().min(1),
|
|
69
|
+
resourceUri: z.string().startsWith('ui://'),
|
|
70
|
+
title: z.string().min(1).optional(),
|
|
71
|
+
result: z.json(),
|
|
72
|
+
arguments: z.json().optional(),
|
|
73
|
+
html: z.string().min(1),
|
|
74
|
+
resourceMeta: z.record(z.string(), z.unknown()).optional(),
|
|
75
|
+
allowedOpenDomains: z.array(z.url().startsWith('https://')).optional(),
|
|
76
|
+
replayed: z.literal(true),
|
|
86
77
|
})
|
|
87
78
|
.strict();
|
|
88
79
|
const assistantModelContentPartSchema = z
|
|
@@ -185,6 +176,9 @@ const eventEnvelope = (event, data) => z.object({ event: z.literal(event), data
|
|
|
185
176
|
* proposal/completion payloads while clients talking to older services tolerate absent new fields.
|
|
186
177
|
*/
|
|
187
178
|
export const assistantWireEventSchema = z.union([
|
|
179
|
+
eventEnvelope('message_started', z.object({ message: z.string().min(1) })),
|
|
180
|
+
eventEnvelope('resume_started', z.object({ tool: z.string() })),
|
|
181
|
+
eventEnvelope('message_completed', z.object({})),
|
|
188
182
|
eventEnvelope('content', z.object({ turnId: optionalTurnId, delta: z.string() })),
|
|
189
183
|
eventEnvelope('tool_started', z.object({
|
|
190
184
|
turnId: optionalTurnId,
|
|
@@ -224,17 +218,9 @@ export const assistantWireEventSchema = z.union([
|
|
|
224
218
|
resourceMeta: z.record(z.string(), z.unknown()).optional(),
|
|
225
219
|
replayed: z.literal(true).optional(),
|
|
226
220
|
})),
|
|
227
|
-
eventEnvelope('view_available',
|
|
221
|
+
eventEnvelope('view_available', recoverableViewSchema.omit({ replayed: true }).extend({
|
|
228
222
|
turnId: optionalTurnId,
|
|
229
|
-
id: z.string().min(1),
|
|
230
|
-
tool: z.string().min(1),
|
|
231
|
-
resourceUri: z.string().startsWith('ui://'),
|
|
232
|
-
title: z.string().min(1).optional(),
|
|
233
|
-
result: z.json(),
|
|
234
|
-
arguments: z.json().optional(),
|
|
235
223
|
html: z.string().min(1).optional(),
|
|
236
|
-
resourceMeta: z.record(z.string(), z.unknown()).optional(),
|
|
237
|
-
allowedOpenDomains: z.array(z.url().startsWith('https://')).optional(),
|
|
238
224
|
replayed: z.literal(true).optional(),
|
|
239
225
|
})),
|
|
240
226
|
eventEnvelope('auth_requested', z.object({
|
|
@@ -31,7 +31,7 @@ Runtime requirements: Node.js 20+ for the server helper; the package ships ESM a
|
|
|
31
31
|
export conditions, so bundlers and plain Node resolve it without aliases or type shims.
|
|
32
32
|
|
|
33
33
|
The full, always-current integration guide (access modes, session response contract, framework notes, and
|
|
34
|
-
troubleshooting) lives at <https://docs.noodleseed.dev/guides/embedded-assistant>. Authoring and deploying
|
|
34
|
+
troubleshooting) lives at <https://docs.noodleseed.dev/docs/guides/embedded-assistant>. Authoring and deploying
|
|
35
35
|
the server itself is `@noodleseed/one` (`npm install -g @noodleseed/one`).
|
|
36
36
|
|
|
37
37
|
If your page sends a `Content-Security-Policy`, allow the Noodle service origin in `connect-src` (turns and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noodleseed/one",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.152.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Noodle CLI by Noodle Seed — author, run, and deploy declarative MCP servers. Embedding the assistant in your own web app is @noodleseed/assistant.",
|
|
6
6
|
"license": "Apache-2.0",
|