@pikku/core 0.12.148 → 0.12.151
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/function/function-runner.js +23 -0
- package/dist/function/trace-queue-service.d.ts +26 -0
- package/dist/function/trace-queue-service.js +48 -0
- package/dist/mesh.d.ts +2 -2
- package/dist/mesh.js +3 -3
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/mesh-auth.d.ts +3 -2
- package/dist/middleware/mesh-auth.js +7 -2
- package/dist/middleware/remote-jobs-secret.d.ts +1 -1
- package/dist/middleware/require-origin.d.ts +19 -0
- package/dist/middleware/require-origin.js +36 -2
- package/dist/services/deployment-service.d.ts +1 -1
- package/dist/services/incoming-webhook-service.d.ts +4 -2
- package/dist/services/incoming-webhook-service.js +4 -3
- package/dist/services/queue-webhook-service.js +7 -1
- package/dist/services/remote-jobs.d.ts +6 -1
- package/dist/services/scheduler-service.d.ts +3 -1
- package/dist/services/webhook-service.d.ts +2 -0
- package/dist/services/workflow-service.d.ts +4 -1
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/queue-identity-transport-tests.d.ts +18 -0
- package/dist/testing/queue-identity-transport-tests.js +162 -0
- package/dist/testing/queue-trace-conformance.d.ts +26 -0
- package/dist/testing/queue-trace-conformance.js +259 -0
- package/dist/testing/service-tests/channel-store-tests.js +11 -0
- package/dist/testing/service-tests/queued-workflow-harness.d.ts +18 -1
- package/dist/testing/service-tests/queued-workflow-harness.js +19 -3
- package/dist/testing/service-tests/workflow-service-tests.js +12 -0
- package/dist/testing/trace-matrix/assertions.d.ts +3 -0
- package/dist/testing/trace-matrix/assertions.js +190 -0
- package/dist/testing/trace-matrix/chain-harness.d.ts +119 -0
- package/dist/testing/trace-matrix/chain-harness.js +777 -0
- package/dist/testing/trace-matrix/dimensions.d.ts +55 -0
- package/dist/testing/trace-matrix/dimensions.js +305 -0
- package/dist/testing/trace-matrix/pairwise.d.ts +20 -0
- package/dist/testing/trace-matrix/pairwise.js +75 -0
- package/dist/testing/trace-matrix/report.d.ts +1 -0
- package/dist/testing/trace-matrix/report.js +16 -0
- package/dist/testing/trace-matrix/transports.d.ts +19 -0
- package/dist/testing/trace-matrix/transports.js +27 -0
- package/dist/testing/trace-matrix/workflow-cases.d.ts +24 -0
- package/dist/testing/trace-matrix/workflow-cases.js +147 -0
- package/dist/trace.d.ts +66 -0
- package/dist/trace.js +97 -0
- package/dist/types/core.types.d.ts +6 -2
- package/dist/wirings/addon/addon-reach.d.ts +3 -0
- package/dist/wirings/addon/addon-reach.js +9 -0
- package/dist/wirings/addon/define-plugin.d.ts +16 -0
- package/dist/wirings/addon/wire-addon.js +5 -0
- package/dist/wirings/addon/wire-remote-addon.d.ts +11 -0
- package/dist/wirings/agent/agent-finalize.d.ts +2 -0
- package/dist/wirings/agent/agent-finalize.js +1 -1
- package/dist/wirings/agent/agent-prepare.d.ts +12 -2
- package/dist/wirings/agent/agent-prepare.js +38 -14
- package/dist/wirings/agent/agent-rpc.js +2 -1
- package/dist/wirings/agent/agent-runner.js +5 -6
- package/dist/wirings/agent/agent-stream.js +6 -6
- package/dist/wirings/agent/voice-input.d.ts +1 -1
- package/dist/wirings/agent/voice-output.d.ts +1 -1
- package/dist/wirings/agent-scorer/agent-scorer-live.d.ts +4 -2
- package/dist/wirings/agent-scorer/agent-scorer-live.js +2 -2
- package/dist/wirings/channel/channel-common.d.ts +4 -1
- package/dist/wirings/channel/channel-common.js +3 -1
- package/dist/wirings/channel/channel-handler.js +2 -0
- package/dist/wirings/channel/channel-host-rpc.d.ts +1 -1
- package/dist/wirings/channel/channel-host-rpc.js +2 -2
- package/dist/wirings/channel/channel-rpc-responder.d.ts +7 -1
- package/dist/wirings/channel/channel-rpc-responder.js +2 -2
- package/dist/wirings/channel/channel-rpc-service.d.ts +1 -1
- package/dist/wirings/channel/channel-rpc-service.js +2 -2
- package/dist/wirings/channel/channel-rpc.types.d.ts +5 -2
- package/dist/wirings/channel/channel-rpc.types.js +1 -1
- package/dist/wirings/channel/channel-store.d.ts +4 -2
- package/dist/wirings/channel/channel-store.js +2 -2
- package/dist/wirings/channel/channel.types.d.ts +3 -0
- package/dist/wirings/channel/local/local-channel-runner.js +16 -5
- package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +2 -0
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +3 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +27 -4
- package/dist/wirings/gateway/gateway-runner.js +3 -1
- package/dist/wirings/http/http-runner.d.ts +4 -4
- package/dist/wirings/http/http-runner.js +14 -18
- package/dist/wirings/http/http.types.d.ts +3 -3
- package/dist/wirings/mcp/mcp-runner.js +15 -5
- package/dist/wirings/queue/in-memory-queue-service.d.ts +1 -1
- package/dist/wirings/queue/in-memory-queue-service.js +8 -2
- package/dist/wirings/queue/index.d.ts +1 -0
- package/dist/wirings/queue/index.js +1 -0
- package/dist/wirings/queue/queue-runner.d.ts +3 -4
- package/dist/wirings/queue/queue-runner.js +8 -7
- package/dist/wirings/queue/queue-trace.d.ts +18 -0
- package/dist/wirings/queue/queue-trace.js +42 -0
- package/dist/wirings/queue/queue.types.d.ts +7 -0
- package/dist/wirings/queue/remote-queue-job.d.ts +1 -1
- package/dist/wirings/queue/remote-queue-job.js +5 -3
- package/dist/wirings/rpc/rpc-runner.d.ts +7 -1
- package/dist/wirings/rpc/rpc-runner.js +43 -21
- package/dist/wirings/rpc/rpc-types.d.ts +2 -0
- package/dist/wirings/scheduler/remote-scheduled-job.d.ts +1 -1
- package/dist/wirings/scheduler/remote-scheduled-job.js +2 -2
- package/dist/wirings/scheduler/scheduler-runner.d.ts +4 -4
- package/dist/wirings/scheduler/scheduler-runner.js +7 -6
- package/dist/wirings/trigger/pikku-trigger-service.js +7 -4
- package/dist/wirings/trigger/webhook-source-runner.d.ts +7 -1
- package/dist/wirings/trigger/webhook-source-runner.js +11 -3
- package/dist/wirings/workflow/graph/graph-runner.d.ts +1 -1
- package/dist/wirings/workflow/graph/graph-runner.js +49 -30
- package/dist/wirings/workflow/index.d.ts +3 -1
- package/dist/wirings/workflow/index.js +1 -0
- package/dist/wirings/workflow/pikku-scenario-service.js +2 -0
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +37 -40
- package/dist/wirings/workflow/pikku-workflow-service.js +122 -133
- package/dist/wirings/workflow/workflow-child-step.d.ts +2 -2
- package/dist/wirings/workflow/workflow-child-step.js +11 -4
- package/dist/wirings/workflow/workflow-compensation.d.ts +6 -0
- package/dist/wirings/workflow/workflow-compensation.js +15 -1
- package/dist/wirings/workflow/workflow-constants.d.ts +13 -0
- package/dist/wirings/workflow/workflow-constants.js +13 -0
- package/dist/wirings/workflow/workflow-dsl-pass.d.ts +2 -0
- package/dist/wirings/workflow/workflow-dsl-pass.js +27 -11
- package/dist/wirings/workflow/workflow-recovery.d.ts +131 -3
- package/dist/wirings/workflow/workflow-recovery.js +233 -7
- package/dist/wirings/workflow/workflow-run-engine.types.d.ts +1 -0
- package/dist/wirings/workflow/workflow-run-mirror.d.ts +4 -0
- package/dist/wirings/workflow/workflow-run-mirror.js +16 -0
- package/dist/wirings/workflow/workflow-run-status.d.ts +2 -0
- package/dist/wirings/workflow/workflow-run-status.js +13 -0
- package/dist/wirings/workflow/workflow-run-trace.d.ts +22 -0
- package/dist/wirings/workflow/workflow-run-trace.js +24 -0
- package/dist/wirings/workflow/workflow-step-claim.d.ts +18 -0
- package/dist/wirings/workflow/workflow-step-claim.js +47 -0
- package/dist/wirings/workflow/workflow-step-retry.d.ts +6 -2
- package/dist/wirings/workflow/workflow-step-retry.js +8 -3
- package/dist/wirings/workflow/workflow-wire.d.ts +12 -0
- package/dist/wirings/workflow/workflow-wire.js +33 -0
- package/dist/wirings/workflow/workflow.types.d.ts +16 -0
- package/package.json +2 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { ConflictError, ForbiddenError, NotFoundError, UnauthorizedError, UnprocessableContentError, } from '../../errors/errors.js';
|
|
2
|
+
import { AbandonedError } from '../../function/abort-scope.js';
|
|
3
|
+
import { RemoteAddonAuthError } from '../../wirings/addon/remote-addon-auth.js';
|
|
4
|
+
import { RemoteAddonFailedError, RemoteAddonTimeoutError, } from '../../wirings/rpc/rpc-runner.js';
|
|
5
|
+
import { QueueJobDiscardedError } from '../../wirings/queue/queue-runner.js';
|
|
6
|
+
import { InMemoryWorkflowService } from '../../wirings/workflow/in-memory-workflow-service.js';
|
|
7
|
+
import { PikkuWorkflowService } from '../../wirings/workflow/pikku-workflow-service.js';
|
|
8
|
+
/** Sleeps go through the scheduler, as in a deployment, so the wake-up is driven by hand. */
|
|
9
|
+
export class ScheduledSleeps extends InMemoryWorkflowService {
|
|
10
|
+
scheduleSleep(...args) {
|
|
11
|
+
return PikkuWorkflowService.prototype['scheduleSleep'].apply(this, args);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** What a step's RPC throws for an outcome: the class a real call would raise. */
|
|
15
|
+
export const outcomeError = (outcome) => {
|
|
16
|
+
switch (outcome) {
|
|
17
|
+
case 'throw-pikku-error':
|
|
18
|
+
case 'step-compensated':
|
|
19
|
+
case 'fan-out-sibling-failure':
|
|
20
|
+
return new ConflictError('refused');
|
|
21
|
+
case 'throw-plain-error':
|
|
22
|
+
case 'job-exhausted':
|
|
23
|
+
return new Error('boom');
|
|
24
|
+
case 'schema-invalid':
|
|
25
|
+
case 'job-poison':
|
|
26
|
+
return new UnprocessableContentError('schema refused the data');
|
|
27
|
+
case 'auth-mesh-jwt':
|
|
28
|
+
return new UnauthorizedError();
|
|
29
|
+
case 'auth-remote-addon':
|
|
30
|
+
return new RemoteAddonAuthError('far', 'resolved token was empty');
|
|
31
|
+
case 'permission-denied':
|
|
32
|
+
return new ForbiddenError();
|
|
33
|
+
case 'remote-4xx':
|
|
34
|
+
return new NotFoundError();
|
|
35
|
+
case 'remote-5xx':
|
|
36
|
+
case 'remote-network':
|
|
37
|
+
return new RemoteAddonFailedError('far', 'fn');
|
|
38
|
+
case 'remote-timeout':
|
|
39
|
+
return new RemoteAddonTimeoutError('far', 'fn', 2);
|
|
40
|
+
case 'job-discarded':
|
|
41
|
+
return new QueueJobDiscardedError('job', 'not wanted');
|
|
42
|
+
case 'abandoned':
|
|
43
|
+
return new AbandonedError('the caller left');
|
|
44
|
+
default:
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const isDsl = (workflow) => workflow.startsWith('dsl');
|
|
49
|
+
/**
|
|
50
|
+
* Registers a workflow named `flow-<id>` that reaches `step`, then has its last
|
|
51
|
+
* RPC meet `outcome`. Returns what brings the run to its end.
|
|
52
|
+
*/
|
|
53
|
+
export const defineRun = (h, run, child = false) => {
|
|
54
|
+
const { id, workflow, step, outcome } = run;
|
|
55
|
+
const queued = workflow.endsWith('-queued');
|
|
56
|
+
const failure = () => outcomeError(outcome);
|
|
57
|
+
let released = false;
|
|
58
|
+
let calls = 0;
|
|
59
|
+
const last = {
|
|
60
|
+
queued,
|
|
61
|
+
forward: async () => {
|
|
62
|
+
const error = failure();
|
|
63
|
+
if (error)
|
|
64
|
+
throw error;
|
|
65
|
+
if (step === 'retry' && ++calls === 1)
|
|
66
|
+
throw new Error('flaky');
|
|
67
|
+
return {};
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
const undoable = step === 'compensation' || outcome === 'step-compensated'
|
|
71
|
+
? { compensate: async () => { } }
|
|
72
|
+
: {};
|
|
73
|
+
h.register(`first-${id}`, {
|
|
74
|
+
queued,
|
|
75
|
+
...undoable,
|
|
76
|
+
forward: async (_data, wire) => {
|
|
77
|
+
if (outcome === 'workflow-cancelled') {
|
|
78
|
+
await h.ws.cancelRun(wire.workflow?.runId ?? wire.workflowStep?.runId, h.rpc);
|
|
79
|
+
}
|
|
80
|
+
return {};
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
h.register(`last-${id}`, last);
|
|
84
|
+
h.register(`left-${id}`, { queued, forward: async () => ({}) });
|
|
85
|
+
const inner = child ? `inner-${id}` : `flow-${id}`;
|
|
86
|
+
if (isDsl(workflow)) {
|
|
87
|
+
h.defineDsl(inner, async (w) => {
|
|
88
|
+
await w.do('First', `first-${id}`, {});
|
|
89
|
+
if (step === 'sleep')
|
|
90
|
+
await w.sleep('Nap', 1);
|
|
91
|
+
if (step === 'suspend' && !released)
|
|
92
|
+
await w.suspend('Hold');
|
|
93
|
+
if (step === 'approval') {
|
|
94
|
+
const decision = await w.approval('Sign off', {
|
|
95
|
+
schema: {
|
|
96
|
+
'~standard': {
|
|
97
|
+
version: 1,
|
|
98
|
+
vendor: 'matrix',
|
|
99
|
+
validate: (value) => ({ value }),
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
if (decision.data?.ok === false) {
|
|
104
|
+
throw new ConflictError('the approval was rejected');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (step === 'fan-out') {
|
|
108
|
+
await Promise.all([
|
|
109
|
+
w.do('Left', `left-${id}`, {}),
|
|
110
|
+
w.do('Last', `last-${id}`, {}),
|
|
111
|
+
]);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
await w.do('Last', `last-${id}`, {}, step === 'retry' ? { retries: 2 } : undefined);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
h.defineGraph(inner, `first-${id}`, {
|
|
120
|
+
[`first-${id}`]: {
|
|
121
|
+
next: step === 'fan-out' ? [`left-${id}`, `last-${id}`] : `last-${id}`,
|
|
122
|
+
},
|
|
123
|
+
[`left-${id}`]: {},
|
|
124
|
+
[`last-${id}`]: step === 'retry' ? { retries: 2 } : {},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (child) {
|
|
128
|
+
h.defineDsl(`flow-${id}`, async (w) => w.do('Child', inner, {}));
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
/** Wakes whatever the run is waiting on, then lets it finish. */
|
|
132
|
+
settle: async (runId, wakeSleeps) => {
|
|
133
|
+
if (step === 'sleep')
|
|
134
|
+
await wakeSleeps();
|
|
135
|
+
if (step === 'suspend') {
|
|
136
|
+
released = true;
|
|
137
|
+
await h.ws.resumeWorkflow(runId);
|
|
138
|
+
}
|
|
139
|
+
if (step === 'approval') {
|
|
140
|
+
await h.ws.approveStep(runId, 'Sign off', {
|
|
141
|
+
ok: outcome !== 'approval-rejected',
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
await h.pump();
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
};
|
package/dist/trace.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Logger } from './services/logger.js';
|
|
2
|
+
/** One invocation's place in a W3C trace. */
|
|
3
|
+
export type TraceContext = {
|
|
4
|
+
/** 32 lowercase hex characters, shared by every hop of the trace. */
|
|
5
|
+
traceId: string;
|
|
6
|
+
/** 16 lowercase hex characters, identifying this invocation. */
|
|
7
|
+
spanId: string;
|
|
8
|
+
/** The caller's span, when the trace was continued from another hop. */
|
|
9
|
+
parentSpanId?: string;
|
|
10
|
+
sampled: boolean;
|
|
11
|
+
};
|
|
12
|
+
/** Whether `value` is a usable trace id: 32 lowercase hex, not all zero. */
|
|
13
|
+
export declare const isValidTraceId: (value: unknown) => value is string;
|
|
14
|
+
/** A new trace, or a new span in `traceId` when one is given. */
|
|
15
|
+
export declare const createTrace: (traceId?: string) => TraceContext;
|
|
16
|
+
/**
|
|
17
|
+
* Reads a W3C `traceparent` header. Returns `undefined` for anything malformed,
|
|
18
|
+
* an all-zero id, version `ff`, or a version `00` header with extra fields.
|
|
19
|
+
*/
|
|
20
|
+
export declare const parseTraceparent: (header: unknown) => (Pick<TraceContext, 'traceId' | 'sampled'> & {
|
|
21
|
+
parentSpanId: string;
|
|
22
|
+
}) | undefined;
|
|
23
|
+
/** Formats `trace` as the `traceparent` of a call it makes: it is the parent. */
|
|
24
|
+
export declare const formatTraceparent: (trace: Pick<TraceContext, 'traceId' | 'spanId' | 'sampled'>) => string;
|
|
25
|
+
/**
|
|
26
|
+
* Resolves the trace for an inbound HTTP request: a valid `traceId` from the
|
|
27
|
+
* runtime, then the `traceparent` header if the deployment opted in, then a new
|
|
28
|
+
* trace.
|
|
29
|
+
*
|
|
30
|
+
* knowledge: decisions/security/inbound-traceparent-is-ignored-until-the-caller-is-authenticated.md
|
|
31
|
+
*/
|
|
32
|
+
export declare const resolveHTTPTrace: (readHeader: () => unknown, logger: Logger, { traceId, trustInboundTraceparent, }: {
|
|
33
|
+
traceId?: string;
|
|
34
|
+
trustInboundTraceparent?: boolean;
|
|
35
|
+
}) => TraceContext;
|
|
36
|
+
/**
|
|
37
|
+
* Starts this hop's span in the trace a job, scheduled task or workflow run
|
|
38
|
+
* carried, or a new trace when it carried nothing usable. A carried value needs
|
|
39
|
+
* no signature: it names a trace, never an identity.
|
|
40
|
+
*/
|
|
41
|
+
export declare const continueTrace: (traceparent: unknown) => TraceContext;
|
|
42
|
+
/**
|
|
43
|
+
* Continues the caller's trace on an already-running invocation. Only for a
|
|
44
|
+
* caller that has been authenticated, and in place because the HTTP runner
|
|
45
|
+
* holds `wire.trace` for its error response.
|
|
46
|
+
*/
|
|
47
|
+
export declare const adoptTraceparent: (wire: {
|
|
48
|
+
traceId?: string;
|
|
49
|
+
trace?: TraceContext;
|
|
50
|
+
}, header: unknown) => void;
|
|
51
|
+
/** `logger` scoped to a trace, so what it writes can be found by that id. */
|
|
52
|
+
export declare const tracedLogger: (logger: Logger, traceId?: string) => Logger;
|
|
53
|
+
/** The wire fields for a hop that continues `traceparent`, or starts a new trace. */
|
|
54
|
+
export declare const traceWire: (traceparent?: unknown) => {
|
|
55
|
+
traceId: string;
|
|
56
|
+
trace: TraceContext;
|
|
57
|
+
};
|
|
58
|
+
/** {@link traceWire} for a child of `parent`, when there is a parent. */
|
|
59
|
+
export declare const childTraceWire: (parent: TraceContext | undefined) => {
|
|
60
|
+
traceId: string;
|
|
61
|
+
trace: TraceContext;
|
|
62
|
+
};
|
|
63
|
+
/** The `traceparent` for a call made from `wire`, if it is in a W3C trace. */
|
|
64
|
+
export declare const outgoingTraceparent: (wire: {
|
|
65
|
+
trace?: TraceContext;
|
|
66
|
+
}) => string | undefined;
|
package/dist/trace.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const TRACE_ID = /^[0-9a-f]{32}$/;
|
|
2
|
+
const TRACEPARENT = /^([0-9a-f]{2})-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})(-.*)?$/;
|
|
3
|
+
const ALL_ZERO = /^0+$/;
|
|
4
|
+
const randomHex = (bytes) => {
|
|
5
|
+
const hex = Array.from(globalThis.crypto.getRandomValues(new Uint8Array(bytes)), (byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
6
|
+
// All zeroes means "invalid" in W3C, so it can never be issued.
|
|
7
|
+
return ALL_ZERO.test(hex) ? randomHex(bytes) : hex;
|
|
8
|
+
};
|
|
9
|
+
/** Whether `value` is a usable trace id: 32 lowercase hex, not all zero. */
|
|
10
|
+
export const isValidTraceId = (value) => typeof value === 'string' && TRACE_ID.test(value) && !ALL_ZERO.test(value);
|
|
11
|
+
/** A new trace, or a new span in `traceId` when one is given. */
|
|
12
|
+
export const createTrace = (traceId) => ({
|
|
13
|
+
traceId: traceId ?? randomHex(16),
|
|
14
|
+
spanId: randomHex(8),
|
|
15
|
+
sampled: true,
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* Reads a W3C `traceparent` header. Returns `undefined` for anything malformed,
|
|
19
|
+
* an all-zero id, version `ff`, or a version `00` header with extra fields.
|
|
20
|
+
*/
|
|
21
|
+
export const parseTraceparent = (header) => {
|
|
22
|
+
if (typeof header !== 'string')
|
|
23
|
+
return undefined;
|
|
24
|
+
const match = TRACEPARENT.exec(header);
|
|
25
|
+
if (!match)
|
|
26
|
+
return undefined;
|
|
27
|
+
const [, version, traceId, parentSpanId, flags, extra] = match;
|
|
28
|
+
if (version === 'ff' || (version === '00' && extra !== undefined)) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
if (ALL_ZERO.test(traceId) || ALL_ZERO.test(parentSpanId))
|
|
32
|
+
return undefined;
|
|
33
|
+
return {
|
|
34
|
+
traceId: traceId,
|
|
35
|
+
parentSpanId: parentSpanId,
|
|
36
|
+
sampled: (Number.parseInt(flags, 16) & 1) === 1,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
/** Formats `trace` as the `traceparent` of a call it makes: it is the parent. */
|
|
40
|
+
export const formatTraceparent = (trace) => `00-${trace.traceId}-${trace.spanId}-${trace.sampled ? '01' : '00'}`;
|
|
41
|
+
/**
|
|
42
|
+
* Resolves the trace for an inbound HTTP request: a valid `traceId` from the
|
|
43
|
+
* runtime, then the `traceparent` header if the deployment opted in, then a new
|
|
44
|
+
* trace.
|
|
45
|
+
*
|
|
46
|
+
* knowledge: decisions/security/inbound-traceparent-is-ignored-until-the-caller-is-authenticated.md
|
|
47
|
+
*/
|
|
48
|
+
export const resolveHTTPTrace = (readHeader, logger, { traceId, trustInboundTraceparent, }) => {
|
|
49
|
+
if (traceId !== undefined) {
|
|
50
|
+
if (isValidTraceId(traceId))
|
|
51
|
+
return createTrace(traceId);
|
|
52
|
+
logger.warn('Ignoring a traceId that is not 32 lowercase hex characters');
|
|
53
|
+
}
|
|
54
|
+
if (trustInboundTraceparent) {
|
|
55
|
+
let header;
|
|
56
|
+
try {
|
|
57
|
+
header = readHeader();
|
|
58
|
+
}
|
|
59
|
+
catch { }
|
|
60
|
+
const inbound = parseTraceparent(header);
|
|
61
|
+
if (inbound)
|
|
62
|
+
return { ...inbound, spanId: randomHex(8) };
|
|
63
|
+
}
|
|
64
|
+
return createTrace();
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Starts this hop's span in the trace a job, scheduled task or workflow run
|
|
68
|
+
* carried, or a new trace when it carried nothing usable. A carried value needs
|
|
69
|
+
* no signature: it names a trace, never an identity.
|
|
70
|
+
*/
|
|
71
|
+
export const continueTrace = (traceparent) => {
|
|
72
|
+
const carried = parseTraceparent(traceparent);
|
|
73
|
+
return carried ? { ...carried, spanId: randomHex(8) } : createTrace();
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Continues the caller's trace on an already-running invocation. Only for a
|
|
77
|
+
* caller that has been authenticated, and in place because the HTTP runner
|
|
78
|
+
* holds `wire.trace` for its error response.
|
|
79
|
+
*/
|
|
80
|
+
export const adoptTraceparent = (wire, header) => {
|
|
81
|
+
const inbound = parseTraceparent(header);
|
|
82
|
+
if (!inbound)
|
|
83
|
+
return;
|
|
84
|
+
wire.traceId = inbound.traceId;
|
|
85
|
+
wire.trace = Object.assign(wire.trace ?? createTrace(inbound.traceId), inbound);
|
|
86
|
+
};
|
|
87
|
+
/** `logger` scoped to a trace, so what it writes can be found by that id. */
|
|
88
|
+
export const tracedLogger = (logger, traceId) => (traceId && logger.scope?.(traceId)) || logger;
|
|
89
|
+
/** The wire fields for a hop that continues `traceparent`, or starts a new trace. */
|
|
90
|
+
export const traceWire = (traceparent) => {
|
|
91
|
+
const trace = continueTrace(traceparent);
|
|
92
|
+
return { traceId: trace.traceId, trace };
|
|
93
|
+
};
|
|
94
|
+
/** {@link traceWire} for a child of `parent`, when there is a parent. */
|
|
95
|
+
export const childTraceWire = (parent) => traceWire(parent && formatTraceparent(parent));
|
|
96
|
+
/** The `traceparent` for a call made from `wire`, if it is in a W3C trace. */
|
|
97
|
+
export const outgoingTraceparent = (wire) => wire.trace && formatTraceparent(wire.trace);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { AbortScope } from '../function/abort-scope.js';
|
|
2
|
+
import type { TraceContext } from '../trace.js';
|
|
3
|
+
export type { TraceContext };
|
|
2
4
|
import type { IncomingWebhookService } from '../services/incoming-webhook-service.js';
|
|
3
5
|
import type { TriggerSourceStore } from '../services/trigger-source-store.js';
|
|
4
6
|
import type { LeaseService } from '../services/lease-service.js';
|
|
@@ -88,7 +90,7 @@ export type CoreConfig<Config extends Record<string, unknown> = {}> = {
|
|
|
88
90
|
/** Refuse a secret that declares no `allowedHosts` rather than treating it as unrestricted. */
|
|
89
91
|
requireAllowedHosts?: boolean;
|
|
90
92
|
};
|
|
91
|
-
workflow?: WorkflowServiceConfig
|
|
93
|
+
workflow?: Partial<WorkflowServiceConfig>;
|
|
92
94
|
webhook?: WebhookServiceConfig;
|
|
93
95
|
postgres?: PostgresConfig;
|
|
94
96
|
} & Config;
|
|
@@ -255,8 +257,10 @@ export type PikkuWire<In = unknown, Out = unknown, HasInitialSession extends boo
|
|
|
255
257
|
* sets it; services that log fall back to the singleton logger.
|
|
256
258
|
*/
|
|
257
259
|
logger: Logger;
|
|
258
|
-
/** Trace ID for distributed tracing — propagated across mesh RPC calls via the
|
|
260
|
+
/** Trace ID for distributed tracing — propagated across mesh RPC calls via the traceparent header */
|
|
259
261
|
traceId: string;
|
|
262
|
+
/** This invocation's place in the trace, when it has a W3C one. */
|
|
263
|
+
trace: TraceContext;
|
|
260
264
|
functionId: string;
|
|
261
265
|
addonNamespace: string;
|
|
262
266
|
http: PikkuHTTP<In>;
|
|
@@ -5,6 +5,9 @@ export declare const addonCallerOf: (wire: PikkuRawWire) => string | undefined;
|
|
|
5
5
|
export declare class AddonNotUsedError extends PikkuError {
|
|
6
6
|
constructor(caller: string, target: string);
|
|
7
7
|
}
|
|
8
|
+
export declare class AddonUsesShadowedError extends PikkuError {
|
|
9
|
+
constructor(name: string, target: string);
|
|
10
|
+
}
|
|
8
11
|
/**
|
|
9
12
|
* The name an addon's call resolves to on this host, through its `uses`.
|
|
10
13
|
*
|
|
@@ -29,6 +29,15 @@ addError(AddonNotUsedError, {
|
|
|
29
29
|
status: 403,
|
|
30
30
|
message: 'Addon called another addon it does not use.',
|
|
31
31
|
});
|
|
32
|
+
export class AddonUsesShadowedError extends PikkuError {
|
|
33
|
+
constructor(name, target) {
|
|
34
|
+
super(`Addon '${name}' maps its own name in 'uses' to '${target}', but a call to '${name}:<function>' always reaches the addon itself, so the mapping can never be used. Mount the addon under another name.`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
addError(AddonUsesShadowedError, {
|
|
38
|
+
status: 500,
|
|
39
|
+
message: 'Addon uses maps its own name.',
|
|
40
|
+
});
|
|
32
41
|
/**
|
|
33
42
|
* The name an addon's call resolves to on this host, through its `uses`.
|
|
34
43
|
*
|
|
@@ -22,6 +22,22 @@ type StudioScreenBase = {
|
|
|
22
22
|
layout?: 'bare';
|
|
23
23
|
/** Hides the screen and its nav for viewers without access. The addon's functions must enforce the same scopes: hiding a screen is not access control. */
|
|
24
24
|
scopes?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* The agent that answers in Studio's chat panel while this screen is open.
|
|
27
|
+
* `'studio:<name>'` names an agent Studio ships (e.g. `'studio:knowledge'`);
|
|
28
|
+
* `pikku all` only checks its format. A bare name is an agent the addon ships:
|
|
29
|
+
* it resolves to `agents/<name>.md` in the addon package: the agent's
|
|
30
|
+
* instructions, which name the skills it follows. Its frontmatter has a
|
|
31
|
+
* `title` and a `description`, both message keys in the addon's catalog.
|
|
32
|
+
* Lowercase letters, digits and hyphens, starting with a letter. Leave it out and the chat is unchanged.
|
|
33
|
+
*/
|
|
34
|
+
agent?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Whether Studio's general Chat tab shows on this screen, beside the
|
|
37
|
+
* screen's agent tab. Defaults to `true`. `false` hides it; with no `agent`
|
|
38
|
+
* the screen then has no chat at all.
|
|
39
|
+
*/
|
|
40
|
+
defaultChat?: boolean;
|
|
25
41
|
} & ({
|
|
26
42
|
/** `'studio'` gives `/<path>`, `'team'` gives `/<team>/<path>`. */
|
|
27
43
|
scope: 'studio' | 'team';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { pikkuState } from '../../pikku-state.js';
|
|
2
2
|
import { getTagGroups } from '../../utils.js';
|
|
3
|
+
import { AddonUsesShadowedError } from './addon-reach.js';
|
|
3
4
|
/**
|
|
4
5
|
* Installs an addon into this project: its functions, wirings and scopes become
|
|
5
6
|
* part of the app, under the namespace and options given here.
|
|
@@ -7,6 +8,10 @@ import { getTagGroups } from '../../utils.js';
|
|
|
7
8
|
* @example snippet: addonWiring
|
|
8
9
|
*/
|
|
9
10
|
export const wireAddon = (config) => {
|
|
11
|
+
const shadowed = config.uses?.[config.name];
|
|
12
|
+
if (shadowed !== undefined && shadowed !== config.name) {
|
|
13
|
+
throw new AddonUsesShadowedError(config.name, shadowed);
|
|
14
|
+
}
|
|
10
15
|
pikkuState(null, 'addons', 'packages').set(config.name, {
|
|
11
16
|
package: config.package,
|
|
12
17
|
rpcEndpoint: config.rpcEndpoint,
|
|
@@ -51,6 +51,17 @@ export type WireRemoteAddonConfig = {
|
|
|
51
51
|
* knowledge: decisions/security/wire-addon-expose-selects-the-rpc-surface.md
|
|
52
52
|
*/
|
|
53
53
|
expose?: boolean | string[];
|
|
54
|
+
/**
|
|
55
|
+
* A package installed in this project that carries the screens and
|
|
56
|
+
* contributors shown under this name, when they live apart from the contract
|
|
57
|
+
* package. Read at build time, never at runtime. `ui` mounts its screens;
|
|
58
|
+
* `contributors` opts in to the ones it registers.
|
|
59
|
+
*/
|
|
60
|
+
local?: {
|
|
61
|
+
package: string;
|
|
62
|
+
ui?: boolean;
|
|
63
|
+
contributors?: string[];
|
|
64
|
+
};
|
|
54
65
|
/** Milliseconds a call may take before it is aborted. Defaults to {@link DEFAULT_REMOTE_ADDON_TIMEOUT_MS}. */
|
|
55
66
|
timeoutMs?: number;
|
|
56
67
|
/** Extra headers for every call to the host. Cannot replace the auth, trace or contract headers. */
|
|
@@ -12,6 +12,8 @@ export type RunUsage = {
|
|
|
12
12
|
* a scorer is shown is exactly what was stored — including the redactions.
|
|
13
13
|
*/
|
|
14
14
|
export type FinalizedRun = {
|
|
15
|
+
/** The trace the run's scoring jobs stay in. */
|
|
16
|
+
traceparent?: string;
|
|
15
17
|
runId: string;
|
|
16
18
|
agentName: string;
|
|
17
19
|
threadId: string;
|
|
@@ -130,7 +130,7 @@ export const finalizeAgentRun = async (agentRunState, run) => {
|
|
|
130
130
|
// Best-effort and last: the client already has its answer, so a grading
|
|
131
131
|
// failure must not surface as a failed run.
|
|
132
132
|
try {
|
|
133
|
-
await scoreFinishedRun(snapshot, services);
|
|
133
|
+
await scoreFinishedRun(snapshot, services, run.traceparent);
|
|
134
134
|
}
|
|
135
135
|
catch (error) {
|
|
136
136
|
services.logger?.error(`[pikku] Live scoring failed for run ${run.runId}`, error);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { CoreUserSession, GetCredential } from '../../types/core.types.js';
|
|
2
2
|
import type { CoreAgent, AgentInput, AgentToolDef, AgentMessage, AgentStreamChannel, PikkuAgentMiddlewareHooks, SessionScope } from './agent.types.js';
|
|
3
|
-
import type { AgentRunnerParams } from '../../services/agent-runner-service.js';
|
|
3
|
+
import type { AgentRunnerParams, AgentRunnerService } from '../../services/agent-runner-service.js';
|
|
4
4
|
import { PikkuError } from '../../errors/error-handler.js';
|
|
5
5
|
import type { SessionService } from '../../services/user-session-service.js';
|
|
6
|
+
import { type TraceContext } from '../../trace.js';
|
|
6
7
|
/**
|
|
7
8
|
* Per-request context for running an agent: the caller's session, credential access and, for
|
|
8
9
|
* a sessionless request, the minted anonymous owner id.
|
|
@@ -13,6 +14,8 @@ export type RunAgentParams = {
|
|
|
13
14
|
getCredential?: GetCredential;
|
|
14
15
|
/** Ephemeral owner identity minted for a sessionless request; never client-supplied, never reused across requests. */
|
|
15
16
|
anonymousOwnerResourceId?: string;
|
|
17
|
+
/** The caller's trace. Each tool call is a span in it. */
|
|
18
|
+
trace?: TraceContext;
|
|
16
19
|
};
|
|
17
20
|
export declare function resolveSessionPrincipal(params: RunAgentParams, sessionScope: SessionScope | undefined): string | undefined;
|
|
18
21
|
export declare function resolveOwnerResourceId(params: RunAgentParams, sessionScope: SessionScope | undefined, requestedResourceId: string): string;
|
|
@@ -155,11 +158,18 @@ export declare function buildToolDefs(params: RunAgentParams, agentSessionMap: M
|
|
|
155
158
|
tools: AgentToolDef[];
|
|
156
159
|
missingRpcs: string[];
|
|
157
160
|
}>;
|
|
161
|
+
/**
|
|
162
|
+
* The singleton `agentRunner`, keyed with the caller's `AI_API_KEY` credential when one is set.
|
|
163
|
+
* Every entry that calls the model (run, stream, approve, resume) goes through this.
|
|
164
|
+
*/
|
|
165
|
+
export declare function resolveAgentRunner(singletonServices: {
|
|
166
|
+
agentRunner?: AgentRunnerService;
|
|
167
|
+
}, params: RunAgentParams): Promise<AgentRunnerService>;
|
|
158
168
|
export declare function prepareAgentRun(agentName: string, input: AgentInput, params: RunAgentParams, agentSessionMap: Map<string, string>, streamContext?: StreamContext): Promise<{
|
|
159
169
|
agent: CoreAgent;
|
|
160
170
|
packageName: string | null;
|
|
161
171
|
resolvedName: string;
|
|
162
|
-
agentRunner:
|
|
172
|
+
agentRunner: AgentRunnerService;
|
|
163
173
|
storage: import("../../services/agent-storage-service.js").AgentStorageService | undefined;
|
|
164
174
|
memoryConfig: import("./agent.types.js").AgentMemoryConfig | undefined;
|
|
165
175
|
threadId: string;
|
|
@@ -11,6 +11,7 @@ import { resolveNamespace, ContextAwareRPCService, } from '../../wirings/rpc/rpc
|
|
|
11
11
|
import { getOrCreatePackageSingletonServices } from '../../wirings/addon/addon-runner.js';
|
|
12
12
|
import { resolveMemoryServices, loadContextMessages, trimMessages, } from './agent-memory.js';
|
|
13
13
|
import { resolveModelConfig } from './agent-model-config.js';
|
|
14
|
+
import { childTraceWire, createTrace, outgoingTraceparent, tracedLogger, } from '../../trace.js';
|
|
14
15
|
export function resolveSessionPrincipal(params, sessionScope) {
|
|
15
16
|
const session = params.sessionService?.get();
|
|
16
17
|
if ((sessionScope ?? 'user') === 'org') {
|
|
@@ -321,6 +322,8 @@ export function buildSubAgentRunInput(message, threadId, resourceId, parentConte
|
|
|
321
322
|
export async function buildToolDefs(params, agentSessionMap, resourceId, agentName, packageName, streamContext, agentMiddlewares, agentMode, parentContext) {
|
|
322
323
|
const singletonServices = getSingletonServices();
|
|
323
324
|
const tools = [];
|
|
325
|
+
// Every tool of a run sits under one trace, whoever started the run.
|
|
326
|
+
const trace = params.trace ?? createTrace();
|
|
324
327
|
const missingRpcs = [];
|
|
325
328
|
const approvalPolicy = streamContext?.options?.requiresToolApproval ?? 'explicit';
|
|
326
329
|
const meta = pikkuState(packageName, 'agent', 'agentsMeta')[agentName];
|
|
@@ -442,9 +445,14 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
442
445
|
approvalDescriptionFn,
|
|
443
446
|
readonly: fnMeta?.readonly || undefined,
|
|
444
447
|
execute: async (toolInput, options) => {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
:
|
|
448
|
+
// The call below is the tool's span, under the run's.
|
|
449
|
+
const wire = {
|
|
450
|
+
traceId: trace.traceId,
|
|
451
|
+
trace,
|
|
452
|
+
...(params.sessionService
|
|
453
|
+
? createMiddlewareSessionWireProps(params.sessionService)
|
|
454
|
+
: {}),
|
|
455
|
+
};
|
|
448
456
|
if (options?.abortScope)
|
|
449
457
|
wire.abortScope = options.abortScope;
|
|
450
458
|
const rpcService = new ContextAwareRPCService(singletonServices, wire, { sessionService: params.sessionService });
|
|
@@ -594,13 +602,21 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
594
602
|
if (!workflowService) {
|
|
595
603
|
throw new Error(`workflowService is not configured — cannot run workflow tool '${workflowName}'`);
|
|
596
604
|
}
|
|
597
|
-
const wire =
|
|
598
|
-
|
|
599
|
-
|
|
605
|
+
const wire = {
|
|
606
|
+
...childTraceWire(trace),
|
|
607
|
+
...(params.sessionService
|
|
608
|
+
? createMiddlewareSessionWireProps(params.sessionService)
|
|
609
|
+
: {}),
|
|
610
|
+
};
|
|
600
611
|
if (options?.abortScope)
|
|
601
612
|
wire.abortScope = options.abortScope;
|
|
602
613
|
const rpcService = new ContextAwareRPCService(singletonServices, wire, { sessionService: params.sessionService });
|
|
603
|
-
return workflowService.runToCompletion(workflowName, toolInput, rpcService, {
|
|
614
|
+
return workflowService.runToCompletion(workflowName, toolInput, rpcService, {
|
|
615
|
+
wire: {
|
|
616
|
+
type: 'internal',
|
|
617
|
+
traceparent: outgoingTraceparent(wire),
|
|
618
|
+
},
|
|
619
|
+
});
|
|
604
620
|
},
|
|
605
621
|
});
|
|
606
622
|
}
|
|
@@ -619,7 +635,7 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
619
635
|
...err.payload,
|
|
620
636
|
};
|
|
621
637
|
}
|
|
622
|
-
singletonServices.logger.error(`AI agent tool '${tool.name}' threw during execute()`, err);
|
|
638
|
+
tracedLogger(singletonServices.logger, trace.traceId).error(`AI agent tool '${tool.name}' threw during execute()`, err);
|
|
623
639
|
throw err;
|
|
624
640
|
}
|
|
625
641
|
};
|
|
@@ -679,20 +695,28 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
679
695
|
}
|
|
680
696
|
return { tools, missingRpcs };
|
|
681
697
|
}
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
698
|
+
/**
|
|
699
|
+
* The singleton `agentRunner`, keyed with the caller's `AI_API_KEY` credential when one is set.
|
|
700
|
+
* Every entry that calls the model (run, stream, approve, resume) goes through this.
|
|
701
|
+
*/
|
|
702
|
+
export async function resolveAgentRunner(singletonServices, params) {
|
|
703
|
+
const agentRunner = singletonServices.agentRunner;
|
|
687
704
|
if (!agentRunner) {
|
|
688
705
|
throw new AIProviderNotConfiguredError();
|
|
689
706
|
}
|
|
690
707
|
if (params.getCredential && agentRunner.withApiKey) {
|
|
691
708
|
const aiCredential = await params.getCredential('AI_API_KEY');
|
|
692
709
|
if (aiCredential?.apiKey?.trim()) {
|
|
693
|
-
|
|
710
|
+
return agentRunner.withApiKey(aiCredential.apiKey);
|
|
694
711
|
}
|
|
695
712
|
}
|
|
713
|
+
return agentRunner;
|
|
714
|
+
}
|
|
715
|
+
export async function prepareAgentRun(agentName, input, params, agentSessionMap, streamContext) {
|
|
716
|
+
const singletonServices = getSingletonServices();
|
|
717
|
+
const { agent, packageName, resolvedName } = resolveAgent(agentName);
|
|
718
|
+
await assertAgentAuthorized(agent, params, packageName);
|
|
719
|
+
const agentRunner = await resolveAgentRunner(singletonServices, params);
|
|
696
720
|
const { storage } = resolveMemoryServices(agent, singletonServices);
|
|
697
721
|
const memoryConfig = agent.memory;
|
|
698
722
|
const threadId = input.threadId;
|
|
@@ -14,6 +14,7 @@ export const createAgentRPC = (wire, options) => {
|
|
|
14
14
|
const params = () => ({
|
|
15
15
|
sessionService: options.sessionService,
|
|
16
16
|
getCredential: wire.getCredential?.bind(wire),
|
|
17
|
+
trace: wire.trace,
|
|
17
18
|
});
|
|
18
19
|
const streamingChannel = () => {
|
|
19
20
|
const channel = wire.channel;
|
|
@@ -50,7 +51,7 @@ export const createAgentRPC = (wire, options) => {
|
|
|
50
51
|
await resumeAgent({ runId, ...input }, wrapChannelWithAGUI(streamingChannel(), { runId }), params(), streamOptions);
|
|
51
52
|
},
|
|
52
53
|
interrupt: async (runId, reason) => interruptAgent({ runId, ...(reason ? { reason } : {}) }, { sessionService: options.sessionService }),
|
|
53
|
-
approve: async (runId, approvals, expectedAgentName) => asRunResult(await resumeAgentSync(runId, approvals,
|
|
54
|
+
approve: async (runId, approvals, expectedAgentName) => asRunResult(await resumeAgentSync(runId, approvals, params(), expectedAgentName === undefined
|
|
54
55
|
? undefined
|
|
55
56
|
: mapAddonCall(wire.addonNamespace, expectedAgentName))),
|
|
56
57
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { outgoingTraceparent } from '../../trace.js';
|
|
1
2
|
import { saveMessages, resolveMemoryServices, loadContextMessages, trimMessages, getWorkingMemoryMiddleware, } from './agent-memory.js';
|
|
2
|
-
import { prepareAgentRun, resolveAgent, buildInstructions, buildToolDefs, resolveOwnerResourceId, agentSessionScope, assertResourcePrincipalOwner, assertRunBelongsToAgent, assertAgentAuthorized, } from './agent-prepare.js';
|
|
3
|
+
import { prepareAgentRun, resolveAgent, buildInstructions, buildToolDefs, resolveOwnerResourceId, agentSessionScope, assertResourcePrincipalOwner, assertRunBelongsToAgent, assertAgentAuthorized, resolveAgentRunner, } from './agent-prepare.js';
|
|
3
4
|
import { checkForApprovals, appendStepMessages } from './agent-stream.js';
|
|
4
5
|
import { AgentInterruptedError, isAbortError, persistOrphanedToolResults, registerInterruptibleRun, trackInterruptNote, trackToolExecution, } from './agent-interrupt.js';
|
|
5
6
|
import { pikkuState, getSingletonServices } from '../../pikku-state.js';
|
|
@@ -7,7 +8,6 @@ import { applyInputMiddleware, describeApprovals, notifyAfterStep, toAccumulated
|
|
|
7
8
|
import { applyOutputMiddleware, finalizeAgentRun, lastUserMessageText, } from './agent-finalize.js';
|
|
8
9
|
import { resolveModelConfig } from './agent-model-config.js';
|
|
9
10
|
import { validateAgentOutput } from './agent-output.js';
|
|
10
|
-
import { AIProviderNotConfiguredError } from '../../errors/errors.js';
|
|
11
11
|
import { deniedToolResult, randomUUID } from './agent-utils.js';
|
|
12
12
|
function stripNulls(obj) {
|
|
13
13
|
if (obj === null)
|
|
@@ -225,6 +225,7 @@ export async function runAgent(agentName, input, params, agentSessionMap) {
|
|
|
225
225
|
uiSpec: structuredOutput.uiSpec,
|
|
226
226
|
});
|
|
227
227
|
await finalizeAgentRun(agentRunState, {
|
|
228
|
+
traceparent: outgoingTraceparent({ trace: params.trace }),
|
|
228
229
|
runId,
|
|
229
230
|
agentName,
|
|
230
231
|
threadId,
|
|
@@ -308,10 +309,7 @@ export async function resumeAgentSync(runId, approvals, params, expectedAgentNam
|
|
|
308
309
|
await assertAgentAuthorized(agent, params, packageName);
|
|
309
310
|
const { storage } = resolveMemoryServices(agent, singletonServices);
|
|
310
311
|
const memoryConfig = agent.memory;
|
|
311
|
-
const agentRunner = singletonServices
|
|
312
|
-
if (!agentRunner) {
|
|
313
|
-
throw new AIProviderNotConfiguredError();
|
|
314
|
-
}
|
|
312
|
+
const agentRunner = await resolveAgentRunner(singletonServices, params);
|
|
315
313
|
const approvedIds = new Set(approvals.filter((a) => a.approved).map((a) => a.toolCallId));
|
|
316
314
|
const rejectedIds = new Set(approvals.filter((a) => !a.approved).map((a) => a.toolCallId));
|
|
317
315
|
const savedPendingApprovals = [...(run.pendingApprovals ?? [])];
|
|
@@ -561,6 +559,7 @@ async function continueAfterToolResultSync(run, agent, packageName, resolvedName
|
|
|
561
559
|
steps: accumulatedSteps,
|
|
562
560
|
});
|
|
563
561
|
await finalizeAgentRun(agentRunState, {
|
|
562
|
+
traceparent: outgoingTraceparent({ trace: params.trace }),
|
|
564
563
|
runId: run.runId,
|
|
565
564
|
agentName: resolvedName,
|
|
566
565
|
threadId: run.threadId,
|