@noodleseed/one 0.151.0 → 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 +2 -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/agent-kit/package.json +1 -1
- 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/managed-spend.d.ts +29 -0
- package/node_modules/@noodle-borg/assistant-gateway/dist/managed-spend.js +27 -1
- 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 +8 -3
- 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/service/package.json +1 -1
- 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 +2 -2
|
@@ -150,6 +150,7 @@ export interface ArtifactStateHandle {
|
|
|
150
150
|
readonly version: string;
|
|
151
151
|
readonly scope: ArtifactStateHandleScope;
|
|
152
152
|
readonly ttlSeconds?: number;
|
|
153
|
+
readonly claimOnAuthentication?: true;
|
|
153
154
|
}
|
|
154
155
|
export interface ArtifactState {
|
|
155
156
|
readonly handles: Readonly<Record<string, ArtifactStateHandle>>;
|
|
@@ -47,8 +47,11 @@
|
|
|
47
47
|
* endpoint claim mappings, resolved operation references may carry ordinary/action endpoint dependency
|
|
48
48
|
* keys, and artifacts carry only endpoint policies. Resolved customer URLs remain request-private runtime
|
|
49
49
|
* state.
|
|
50
|
+
*
|
|
51
|
+
* `0.16.0` (Anonymous-to-authenticated onboarding): additive — finite caller-scoped state handles may
|
|
52
|
+
* opt into atomic ownership adoption when a single-use assistant sign-in ticket is spent.
|
|
50
53
|
*/
|
|
51
|
-
export declare const ARTIFACT_SCHEMA_VERSION = "0.
|
|
54
|
+
export declare const ARTIFACT_SCHEMA_VERSION = "0.16.0";
|
|
52
55
|
/** mimeType for an MCP Apps UI resource (SEP-1865). Widgets are served under this profile. */
|
|
53
56
|
export declare const MCP_APP_MIME_TYPE = "text/html;profile=mcp-app";
|
|
54
57
|
//# sourceMappingURL=version.d.ts.map
|
|
@@ -47,8 +47,11 @@
|
|
|
47
47
|
* endpoint claim mappings, resolved operation references may carry ordinary/action endpoint dependency
|
|
48
48
|
* keys, and artifacts carry only endpoint policies. Resolved customer URLs remain request-private runtime
|
|
49
49
|
* state.
|
|
50
|
+
*
|
|
51
|
+
* `0.16.0` (Anonymous-to-authenticated onboarding): additive — finite caller-scoped state handles may
|
|
52
|
+
* opt into atomic ownership adoption when a single-use assistant sign-in ticket is spent.
|
|
50
53
|
*/
|
|
51
|
-
export const ARTIFACT_SCHEMA_VERSION = '0.
|
|
54
|
+
export const ARTIFACT_SCHEMA_VERSION = '0.16.0';
|
|
52
55
|
/** mimeType for an MCP Apps UI resource (SEP-1865). Widgets are served under this profile. */
|
|
53
56
|
export const MCP_APP_MIME_TYPE = 'text/html;profile=mcp-app';
|
|
54
57
|
//# sourceMappingURL=version.js.map
|
|
@@ -25,6 +25,7 @@ export declare const manifestV1Schema: z.ZodObject<{
|
|
|
25
25
|
caller: "caller";
|
|
26
26
|
}>>;
|
|
27
27
|
ttlSeconds: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
claimOnAuthentication: z.ZodOptional<z.ZodLiteral<true>>;
|
|
28
29
|
}, z.core.$strict>>;
|
|
29
30
|
}, z.core.$strict>>;
|
|
30
31
|
requires: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
|
@@ -549,6 +550,7 @@ export declare const manifestV2Schema: z.ZodObject<{
|
|
|
549
550
|
caller: "caller";
|
|
550
551
|
}>>;
|
|
551
552
|
ttlSeconds: z.ZodOptional<z.ZodNumber>;
|
|
553
|
+
claimOnAuthentication: z.ZodOptional<z.ZodLiteral<true>>;
|
|
552
554
|
}, z.core.$strict>>;
|
|
553
555
|
}, z.core.$strict>>;
|
|
554
556
|
requires: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
|
@@ -1199,6 +1201,7 @@ export declare const manifestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
1199
1201
|
caller: "caller";
|
|
1200
1202
|
}>>;
|
|
1201
1203
|
ttlSeconds: z.ZodOptional<z.ZodNumber>;
|
|
1204
|
+
claimOnAuthentication: z.ZodOptional<z.ZodLiteral<true>>;
|
|
1202
1205
|
}, z.core.$strict>>;
|
|
1203
1206
|
}, z.core.$strict>>;
|
|
1204
1207
|
requires: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
|
@@ -1722,6 +1725,7 @@ export declare const manifestSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
1722
1725
|
caller: "caller";
|
|
1723
1726
|
}>>;
|
|
1724
1727
|
ttlSeconds: z.ZodOptional<z.ZodNumber>;
|
|
1728
|
+
claimOnAuthentication: z.ZodOptional<z.ZodLiteral<true>>;
|
|
1725
1729
|
}, z.core.$strict>>;
|
|
1726
1730
|
}, z.core.$strict>>;
|
|
1727
1731
|
requires: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
|
@@ -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, 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';
|
|
@@ -122,7 +122,7 @@ export async function runAgentTurn(target, session, message, context, deps, emit
|
|
|
122
122
|
stats.reasoningTokens += completion.usage?.reasoningTokens ?? 0;
|
|
123
123
|
stats.totalTokens += completion.usage?.totalTokens ?? 0;
|
|
124
124
|
if (remainingTokens !== undefined) {
|
|
125
|
-
remainingTokens =
|
|
125
|
+
remainingTokens = remainingTurnTokens(remainingTokens, completion.usage, requestTokenLimit);
|
|
126
126
|
}
|
|
127
127
|
const response = completion.choices[0]?.message;
|
|
128
128
|
if (!response)
|
|
@@ -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
|
: {}),
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
41
41
|
"@noodle-borg/admission-limits": "0.0.0",
|
|
42
|
-
"@noodle-borg/agent-kit": "0.
|
|
42
|
+
"@noodle-borg/agent-kit": "0.91.0",
|
|
43
43
|
"@noodle-borg/app-package": "0.0.0",
|
|
44
44
|
"@noodle-borg/assistant-gateway": "0.0.0",
|
|
45
45
|
"@noodle-borg/auth": "0.0.0",
|
|
@@ -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",
|
|
@@ -236,7 +236,7 @@
|
|
|
236
236
|
"@modelcontextprotocol/client": "2.0.0",
|
|
237
237
|
"@modelcontextprotocol/server": "2.0.0",
|
|
238
238
|
"@noodle-borg/admission-limits": "0.0.0",
|
|
239
|
-
"@noodle-borg/agent-kit": "0.
|
|
239
|
+
"@noodle-borg/agent-kit": "0.91.0",
|
|
240
240
|
"@noodle-borg/app-audit": "0.0.0",
|
|
241
241
|
"@noodle-borg/app-package": "0.0.0",
|
|
242
242
|
"@noodle-borg/assistant-gateway": "0.0.0",
|