@crouter/api 0.3.382 → 0.3.384
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/api/__tests__/error-codes.test.js +1 -0
- package/dist/api/client.d.ts +15 -0
- package/dist/api/client.js +74 -9
- package/dist/api/dto/grants.d.ts +4 -0
- package/dist/api/dto/nodes.d.ts +3 -0
- package/dist/api/dto/reports.d.ts +10 -8
- package/dist/api/dto/structured-requests.d.ts +64 -0
- package/dist/api/dto/structured-requests.js +5 -0
- package/dist/api/error-codes.d.ts +5 -0
- package/dist/api/error-codes.js +2 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -0
- package/dist/shared/generated-context.d.ts +1 -1
- package/dist/shared/generated-context.js +3 -3
- package/package.json +1 -1
|
@@ -14,6 +14,7 @@ test('SDK and API expose one fixed code table with contract 2 tuples', () => {
|
|
|
14
14
|
for (const code of ['grant_revoked', 'grant_removed', 'grant_suspended', 'refresh_token_expired', 'refresh_token_reused']) {
|
|
15
15
|
assert.deepEqual(errorCodes[code], { type: 'authentication_error', status: 401, retryable: false }, code);
|
|
16
16
|
}
|
|
17
|
+
assert.deepEqual(errorCodes.provider_setup_pending, { type: 'permission_error', status: 403, retryable: false });
|
|
17
18
|
assert.equal('provider_error' in errorCodes, false); // provider's 4xx status varies
|
|
18
19
|
assert.equal('usage' in errorCodes, false); // legacy socket-only code
|
|
19
20
|
assert.equal('stream_gap' in errorCodes, false); // stream protocol, not a fixed HTTP row
|
package/dist/api/client.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { NodeEventsQuery } from './dto/node-events.js';
|
|
|
7
7
|
import type { BrokerSignalLineDTO } from './dto/broker-signals.js';
|
|
8
8
|
import type { NodeLogAppendRequest, NodeLogAppendResultDTO, NodeTelemetryRecordRequest, NodeRecapRecordRequest, NodeMessageBodyDTO, NodePushedFinalRequest, NodePushedFinalResultDTO } from './dto/node-records.js';
|
|
9
9
|
import type { InterruptResultDTO, MessageResultDTO, SendMessageRequest } from './dto/messages.js';
|
|
10
|
+
import type { CreateStructuredRequest, CreateStructuredRequestResponse, StructuredRequestDTO } from './dto/structured-requests.js';
|
|
10
11
|
import type { PushReportRequest, PushReportResultDTO, ReportDTO, ReportsQuery, SubmitResultDTO, SubmitResultRequest } from './dto/reports.js';
|
|
11
12
|
import type { CloseRequest, CloseResultDTO, PromoteRequest, RelaunchRootResultDTO, ReviveRequest, ReviveResultDTO, WaitRequest, YieldRequest } from './dto/lifecycle.js';
|
|
12
13
|
import type { SubscribeRequest, SubscriptionDTO } from './dto/subscriptions.js';
|
|
@@ -78,6 +79,10 @@ export interface CrtrRequestOptions {
|
|
|
78
79
|
signal?: AbortSignal;
|
|
79
80
|
timeout?: number;
|
|
80
81
|
maxRetries?: number;
|
|
82
|
+
/** Limits the full call — every attempt, response body, and cold-socket or
|
|
83
|
+
* interrupted-response recovery — to one wall-clock budget, without changing
|
|
84
|
+
* the client's default inactivity timeout. */
|
|
85
|
+
budgetMs?: number;
|
|
81
86
|
}
|
|
82
87
|
export declare class CrtrClient {
|
|
83
88
|
private readonly baseUrl;
|
|
@@ -128,6 +133,12 @@ export declare class CrtrClient {
|
|
|
128
133
|
/** Parsed NDJSON hints, consumed eagerly and line by line. The caller must
|
|
129
134
|
* cancel with `signal` when done; no wall-clock timeout applies to the stream. */
|
|
130
135
|
getBrokerSignals(id: string, executionId: string, options?: Omit<CrtrRequestOptions, 'timeout'>): AsyncIterable<BrokerSignalLineDTO>;
|
|
136
|
+
createStructuredRequest(req: CreateStructuredRequest, options?: CrtrRequestOptions): Promise<CreateStructuredRequestResponse>;
|
|
137
|
+
getStructuredRequest(requestId: string, { wait, budgetMs }?: {
|
|
138
|
+
wait?: number;
|
|
139
|
+
budgetMs?: number;
|
|
140
|
+
}): Promise<StructuredRequestDTO>;
|
|
141
|
+
cancelStructuredRequest(requestId: string, options?: CrtrRequestOptions): Promise<StructuredRequestDTO>;
|
|
131
142
|
/** Register or replace an armed target for terminal-outcome delivery. */
|
|
132
143
|
registerOutcomeDelivery(id: string, req: RegisterOutcomeDeliveryRequest): Promise<OutcomeDeliveryDTO>;
|
|
133
144
|
getOutcomeDelivery(id: string): Promise<OutcomeDeliveryDTO>;
|
|
@@ -417,6 +428,10 @@ export declare class CrtrClient {
|
|
|
417
428
|
* only — POST/PATCH are never replayed once a request has actually been
|
|
418
429
|
* sent). No JSON parse; every wrapper goes through here. */
|
|
419
430
|
private send;
|
|
431
|
+
private resolveBudget;
|
|
432
|
+
private awaitWithinBudget;
|
|
433
|
+
/** One transport attempt, deliberately without retry, cold-socket, or interrupted-response recovery. */
|
|
434
|
+
private sendOnce;
|
|
420
435
|
private nodePath;
|
|
421
436
|
/** Validate a background job id before route construction. Job ids arrive
|
|
422
437
|
* from the daemon's file-backed roster and must remain one path segment. */
|
package/dist/api/client.js
CHANGED
|
@@ -37,6 +37,7 @@ export async function waitForDaemonAvailability({ windowMs, probe, initialError,
|
|
|
37
37
|
await sleep(Math.min(pollIntervalMs, afterProbe));
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
+
const budgetExhausted = () => Object.assign(new Error('request budget exhausted'), { code: 'ETIMEDOUT' });
|
|
40
41
|
export class CrtrClient {
|
|
41
42
|
baseUrl;
|
|
42
43
|
fetch;
|
|
@@ -193,6 +194,24 @@ export class CrtrClient {
|
|
|
193
194
|
await reader.cancel().catch(() => { });
|
|
194
195
|
}
|
|
195
196
|
}
|
|
197
|
+
// Structured requests
|
|
198
|
+
createStructuredRequest(req, options) {
|
|
199
|
+
// A synchronous admission is one held exchange. Replaying a POST after a
|
|
200
|
+
// reset can create work the caller has already stopped waiting for, and
|
|
201
|
+
// cold-socket recovery consumes its fixed end-to-end budget.
|
|
202
|
+
if (req.mode === 'sync')
|
|
203
|
+
return this.sendOnce('POST', '/v1/structured-requests', req, options);
|
|
204
|
+
return this.request('POST', '/v1/structured-requests', req, options);
|
|
205
|
+
}
|
|
206
|
+
getStructuredRequest(requestId, { wait = 0, budgetMs } = {}) {
|
|
207
|
+
if (!Number.isInteger(wait) || wait < 0 || wait > 25) {
|
|
208
|
+
throw new RangeError('wait must be an integer between 0 and 25');
|
|
209
|
+
}
|
|
210
|
+
return this.request('GET', withQuery(`/v1/structured-requests/${this.requestPath(requestId)}`, { wait }), undefined, { budgetMs });
|
|
211
|
+
}
|
|
212
|
+
cancelStructuredRequest(requestId, options) {
|
|
213
|
+
return this.request('POST', `/v1/structured-requests/${this.requestPath(requestId)}/cancel`, {}, options);
|
|
214
|
+
}
|
|
196
215
|
/** Register or replace an armed target for terminal-outcome delivery. */
|
|
197
216
|
registerOutcomeDelivery(id, req) {
|
|
198
217
|
return this.request('PUT', routes.nodeOutcomeDelivery(this.nodePath(id)), req);
|
|
@@ -808,7 +827,8 @@ export class CrtrClient {
|
|
|
808
827
|
* the §7 retry policy (connection errors and 429/5xx on GET/HEAD/DELETE
|
|
809
828
|
* only — POST/PATCH are never replayed once a request has actually been
|
|
810
829
|
* sent). No JSON parse; every wrapper goes through here. */
|
|
811
|
-
async send(method, path, body,
|
|
830
|
+
async send(method, path, body, callOpts = {}) {
|
|
831
|
+
const opts = this.resolveBudget(callOpts);
|
|
812
832
|
const idempotent = method === 'GET' || method === 'HEAD' || method === 'DELETE';
|
|
813
833
|
const maxRetries = opts.maxRetries ?? this.maxRetries;
|
|
814
834
|
for (let attempt = 0;; attempt++) {
|
|
@@ -819,7 +839,7 @@ export class CrtrClient {
|
|
|
819
839
|
catch (err) {
|
|
820
840
|
if (this.isColdSocketError(err)) {
|
|
821
841
|
try {
|
|
822
|
-
await this.handleColdSocket(err);
|
|
842
|
+
await this.handleColdSocket(err, opts.deadlineAt);
|
|
823
843
|
response = await this.transport(method, path, body, opts);
|
|
824
844
|
}
|
|
825
845
|
catch (recoveryError) {
|
|
@@ -846,6 +866,42 @@ export class CrtrClient {
|
|
|
846
866
|
}
|
|
847
867
|
}
|
|
848
868
|
// internals
|
|
869
|
+
resolveBudget(opts) {
|
|
870
|
+
const { budgetMs, ...rest } = opts;
|
|
871
|
+
if (budgetMs === undefined)
|
|
872
|
+
return rest;
|
|
873
|
+
if (!Number.isFinite(budgetMs) || budgetMs <= 0)
|
|
874
|
+
throw new RangeError('budgetMs must be a positive finite number');
|
|
875
|
+
return { ...rest, deadlineAt: Date.now() + budgetMs };
|
|
876
|
+
}
|
|
877
|
+
async awaitWithinBudget(promise, deadlineAt) {
|
|
878
|
+
if (deadlineAt === undefined)
|
|
879
|
+
return promise;
|
|
880
|
+
const remainingMs = deadlineAt - Date.now();
|
|
881
|
+
if (remainingMs <= 0)
|
|
882
|
+
throw budgetExhausted();
|
|
883
|
+
let timer;
|
|
884
|
+
try {
|
|
885
|
+
return await Promise.race([
|
|
886
|
+
promise,
|
|
887
|
+
new Promise((_resolve, reject) => { timer = setTimeout(() => reject(budgetExhausted()), remainingMs); }),
|
|
888
|
+
]);
|
|
889
|
+
}
|
|
890
|
+
finally {
|
|
891
|
+
if (timer !== undefined)
|
|
892
|
+
clearTimeout(timer);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
/** One transport attempt, deliberately without retry, cold-socket, or interrupted-response recovery. */
|
|
896
|
+
async sendOnce(method, path, body, callOpts = {}) {
|
|
897
|
+
const opts = this.resolveBudget(callOpts);
|
|
898
|
+
try {
|
|
899
|
+
return await parse(await this.transport(method, path, body, opts));
|
|
900
|
+
}
|
|
901
|
+
catch (error) {
|
|
902
|
+
throw toTransportApiError(error, opts.signal);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
849
905
|
nodePath(id) {
|
|
850
906
|
if (!isSafeNodeId(id)) {
|
|
851
907
|
throw new ApiError(400, 'invalid_node_id', `invalid node id: ${JSON.stringify(id)}`);
|
|
@@ -913,11 +969,17 @@ export class CrtrClient {
|
|
|
913
969
|
* stays an unread `ReadableStream` on the returned `Response`, so a caller
|
|
914
970
|
* that wants to stream (SSE, later) never waits on a buffered body. */
|
|
915
971
|
transport(method, path, body, opts = {}) {
|
|
972
|
+
const remainingBudgetMs = opts.deadlineAt === undefined ? undefined : opts.deadlineAt - Date.now();
|
|
973
|
+
if (remainingBudgetMs !== undefined && remainingBudgetMs <= 0)
|
|
974
|
+
return Promise.reject(budgetExhausted());
|
|
916
975
|
const payload = body === undefined ? undefined : JSON.stringify(body);
|
|
917
976
|
const headers = { accept: 'application/json', ...this.headers, ...opts.headers };
|
|
918
977
|
if (payload !== undefined)
|
|
919
978
|
headers['content-type'] = 'application/json';
|
|
920
|
-
const
|
|
979
|
+
const baseTimeoutMs = opts.timeout ?? this.timeoutMs;
|
|
980
|
+
const timeoutMs = remainingBudgetMs === undefined
|
|
981
|
+
? baseTimeoutMs
|
|
982
|
+
: baseTimeoutMs > 0 ? Math.min(baseTimeoutMs, remainingBudgetMs) : remainingBudgetMs;
|
|
921
983
|
const controller = new AbortController();
|
|
922
984
|
const timer = timeoutMs > 0
|
|
923
985
|
? setTimeout(() => controller.abort(new DOMException('request timed out', 'TimeoutError')), timeoutMs)
|
|
@@ -993,7 +1055,7 @@ export class CrtrClient {
|
|
|
993
1055
|
* it never replays. */
|
|
994
1056
|
async rideOutInterruptedRequest(method, path, body, opts = {}) {
|
|
995
1057
|
try {
|
|
996
|
-
await this.awaitAvailability();
|
|
1058
|
+
await this.awaitAvailability(undefined, opts.deadlineAt);
|
|
997
1059
|
}
|
|
998
1060
|
catch (error) {
|
|
999
1061
|
throw toTransportApiError(error, opts.signal);
|
|
@@ -1008,9 +1070,12 @@ export class CrtrClient {
|
|
|
1008
1070
|
throw toTransportApiError(err, opts.signal);
|
|
1009
1071
|
}
|
|
1010
1072
|
}
|
|
1011
|
-
async awaitAvailability(initialError) {
|
|
1073
|
+
async awaitAvailability(initialError, deadlineAt) {
|
|
1074
|
+
const remainingBudgetMs = deadlineAt === undefined ? undefined : deadlineAt - Date.now();
|
|
1075
|
+
if (remainingBudgetMs !== undefined && remainingBudgetMs <= 0)
|
|
1076
|
+
throw budgetExhausted();
|
|
1012
1077
|
await waitForDaemonAvailability({
|
|
1013
|
-
windowMs: this.coldStartPollWindowMs,
|
|
1078
|
+
windowMs: Math.min(this.coldStartPollWindowMs, remainingBudgetMs ?? this.coldStartPollWindowMs),
|
|
1014
1079
|
initialError,
|
|
1015
1080
|
probe: async (timeoutMs) => {
|
|
1016
1081
|
const response = await this.transport('GET', routes.healthz(), undefined, { timeout: timeoutMs });
|
|
@@ -1034,14 +1099,14 @@ export class CrtrClient {
|
|
|
1034
1099
|
/** Optionally start the daemon, then observe availability before retrying the
|
|
1035
1100
|
* request. Waiting is independent from permission to spawn: externally
|
|
1036
1101
|
* managed daemons still get the same bounded readiness window. */
|
|
1037
|
-
async handleColdSocket(initialError) {
|
|
1102
|
+
async handleColdSocket(initialError, deadlineAt) {
|
|
1038
1103
|
const startedHere = this.autostart && this.onColdSocket !== undefined && !this.coldStartAttempted;
|
|
1039
1104
|
if (startedHere) {
|
|
1040
1105
|
this.coldStartAttempted = true;
|
|
1041
|
-
await this.onColdSocket();
|
|
1106
|
+
await this.awaitWithinBudget(this.onColdSocket(), deadlineAt);
|
|
1042
1107
|
}
|
|
1043
1108
|
try {
|
|
1044
|
-
await this.awaitAvailability(initialError);
|
|
1109
|
+
await this.awaitAvailability(initialError, deadlineAt);
|
|
1045
1110
|
}
|
|
1046
1111
|
catch (error) {
|
|
1047
1112
|
if (startedHere) {
|
package/dist/api/dto/grants.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** A provider's setup state for the account (directory spec, "Provider setup state"). */
|
|
2
|
+
export type SetupState = 'not_started' | 'pending' | 'ready' | 'failed';
|
|
1
3
|
export interface GrantGetDTO {
|
|
2
4
|
sub: string;
|
|
3
5
|
grantee: string;
|
|
@@ -11,4 +13,6 @@ export interface GrantGetDTO {
|
|
|
11
13
|
}[];
|
|
12
14
|
spend_cap: number | null;
|
|
13
15
|
payer: 'user';
|
|
16
|
+
/** `{ <provider id>: <setup state> }` as the directory's grant sync carried it; `{}` when the grantee has none. The daemon performs no `requires` check: an app polls this and refuses its own operation with `provider_setup_pending`. */
|
|
17
|
+
dependencies: Record<string, SetupState>;
|
|
14
18
|
}
|
package/dist/api/dto/nodes.d.ts
CHANGED
|
@@ -69,6 +69,9 @@ export interface CreateNodeRequest {
|
|
|
69
69
|
* validated and duplicate-rejected server-side (`NodeIdConflictError` →
|
|
70
70
|
* HTTP 409 `node_id_exists`). See `crtr node new --node-id`. */
|
|
71
71
|
node_id?: string;
|
|
72
|
+
/** Opaque key generated once per create attempt. A repeated key returns the
|
|
73
|
+
* node created by its first served request. */
|
|
74
|
+
request_key?: string;
|
|
72
75
|
/** Serve this create from the warm pool when a pre-booted spare matches the
|
|
73
76
|
* request's frozen launch tuple (kind, mode, resolved cwd, profile, model,
|
|
74
77
|
* situational_context) — answering in milliseconds instead of waiting out a
|
|
@@ -40,20 +40,22 @@ export interface DeclinedResultDTO {
|
|
|
40
40
|
code: string;
|
|
41
41
|
retryable: boolean;
|
|
42
42
|
}
|
|
43
|
-
/** `POST /v1/nodes/{id}/result` body ({id} = the submitting node).
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
43
|
+
/** `POST /v1/nodes/{id}/result` body ({id} = the submitting node). `request_id`
|
|
44
|
+
* identifies the pending structured request. Either `value` is validated
|
|
45
|
+
* against that request's schema — any JSON value (including null) is legal
|
|
46
|
+
* input — or a decline carries the reason sentence, requester-classified
|
|
47
|
+
* code, and retry claim. A decline records a `failure` outcome with reason
|
|
48
|
+
* `declined` carrying all three and clears the request without validating
|
|
49
|
+
* anything. */
|
|
50
50
|
export type SubmitResultRequest = {
|
|
51
|
+
request_id: string;
|
|
52
|
+
} & ({
|
|
51
53
|
value: unknown;
|
|
52
54
|
} | {
|
|
53
55
|
decline: string;
|
|
54
56
|
code: string;
|
|
55
57
|
retryable: boolean;
|
|
56
|
-
};
|
|
58
|
+
});
|
|
57
59
|
/** Result of a structured-result submission (`crtr push result`). Terminal
|
|
58
60
|
* mode reuses the final-push machinery, so `transitioned` and the managed-worktree
|
|
59
61
|
* closure fields carry the same meaning as on PushReportResultDTO. */
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { NodeOutcomeDetailV1 } from './node-outcomes.js';
|
|
2
|
+
import type { CreateNodeRequest } from './nodes.js';
|
|
3
|
+
import type { IsoTime, NodeIdDTO, TerminalReasonDTO } from './common.js';
|
|
4
|
+
import type { DeclinedResultDTO } from './reports.js';
|
|
5
|
+
/** Fixed end-to-end work allowance for synchronous structured requests. */
|
|
6
|
+
export declare const SYNC_WORK_BUDGET_MS = 60000;
|
|
7
|
+
/** Local transport time retained after a synchronous request's work deadline. */
|
|
8
|
+
export declare const TRANSPORT_MARGIN_MS = 5000;
|
|
9
|
+
export type StructuredRequestModeDTO = 'sync' | 'async';
|
|
10
|
+
export type StructuredRequestSubmissionDTO = 'terminal' | 'oneoff';
|
|
11
|
+
export type StructuredRequestStateDTO = 'pending' | 'completed' | 'declined' | 'expired' | 'canceled' | 'failed';
|
|
12
|
+
/** A JSON Schema object. Schema interpretation and validation are daemon-owned. */
|
|
13
|
+
export type JsonSchemaDTO = Record<string, unknown>;
|
|
14
|
+
/** Reasons that can fail a structured request before or after its node starts. */
|
|
15
|
+
export type StructuredFailureReasonDTO = TerminalReasonDTO | 'node_create_failed' | 'bind_failed' | 'prompt_delivery_failed' | 'node_deadline_exceeded';
|
|
16
|
+
export interface StructuredRequestFailureDTO {
|
|
17
|
+
reason: StructuredFailureReasonDTO;
|
|
18
|
+
detail: NodeOutcomeDetailV1 | null;
|
|
19
|
+
}
|
|
20
|
+
/** Durable authoritative state for one structured request. */
|
|
21
|
+
export interface StructuredRequestDTO {
|
|
22
|
+
request_id: string;
|
|
23
|
+
node_id: NodeIdDTO | null;
|
|
24
|
+
mode: StructuredRequestModeDTO;
|
|
25
|
+
submission: StructuredRequestSubmissionDTO;
|
|
26
|
+
state: StructuredRequestStateDTO;
|
|
27
|
+
created_at: IsoTime;
|
|
28
|
+
deadline_at: IsoTime | null;
|
|
29
|
+
settled_at: IsoTime | null;
|
|
30
|
+
result: unknown | null;
|
|
31
|
+
declined: DeclinedResultDTO | null;
|
|
32
|
+
failure: StructuredRequestFailureDTO | null;
|
|
33
|
+
}
|
|
34
|
+
export type CreateStructuredRequestTarget = {
|
|
35
|
+
kind: 'new';
|
|
36
|
+
create: CreateNodeRequest;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'node';
|
|
39
|
+
node_id: NodeIdDTO;
|
|
40
|
+
};
|
|
41
|
+
/** `POST /v1/structured-requests` body. */
|
|
42
|
+
export interface CreateStructuredRequest {
|
|
43
|
+
request_id: string;
|
|
44
|
+
mode: StructuredRequestModeDTO;
|
|
45
|
+
target: CreateStructuredRequestTarget;
|
|
46
|
+
output_schema: JsonSchemaDTO;
|
|
47
|
+
prompt: string;
|
|
48
|
+
/** An absolute deadline propagated unchanged by callers that already have one. */
|
|
49
|
+
deadline_at?: IsoTime;
|
|
50
|
+
/** Requested duration only when establishing a deadline. */
|
|
51
|
+
work_budget_ms?: number;
|
|
52
|
+
}
|
|
53
|
+
/** An honest admission response: no request record exists when admission runs out of budget. */
|
|
54
|
+
export type CreateStructuredRequestResponse = {
|
|
55
|
+
admitted: true;
|
|
56
|
+
request: StructuredRequestDTO;
|
|
57
|
+
} | {
|
|
58
|
+
admitted: false;
|
|
59
|
+
reason: 'work_budget_exhausted';
|
|
60
|
+
};
|
|
61
|
+
/** `GET /v1/structured-requests/{request_id}` query. */
|
|
62
|
+
export interface ReadStructuredRequestQuery {
|
|
63
|
+
wait?: number;
|
|
64
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Structured-request API DTOs.
|
|
2
|
+
/** Fixed end-to-end work allowance for synchronous structured requests. */
|
|
3
|
+
export const SYNC_WORK_BUDGET_MS = 60_000;
|
|
4
|
+
/** Local transport time retained after a synchronous request's work deadline. */
|
|
5
|
+
export const TRANSPORT_MARGIN_MS = 5_000;
|
|
@@ -69,6 +69,11 @@ export declare const errorCodes: {
|
|
|
69
69
|
readonly status: 403;
|
|
70
70
|
readonly retryable: false;
|
|
71
71
|
};
|
|
72
|
+
readonly provider_setup_pending: {
|
|
73
|
+
readonly type: "permission_error";
|
|
74
|
+
readonly status: 403;
|
|
75
|
+
readonly retryable: false;
|
|
76
|
+
};
|
|
72
77
|
readonly question_pages_off: {
|
|
73
78
|
readonly type: "permission_error";
|
|
74
79
|
readonly status: 403;
|
package/dist/api/error-codes.js
CHANGED
|
@@ -18,6 +18,8 @@ export const errorCodes = {
|
|
|
18
18
|
user_denied: { type: 'permission_error', status: 403, retryable: false },
|
|
19
19
|
provider_refused: { type: 'permission_error', status: 403, retryable: false },
|
|
20
20
|
provider_not_connected: { type: 'permission_error', status: 403, retryable: false },
|
|
21
|
+
// An app refusing its own operation because a provider in its `requires` is not `ready`; details `{ provider, state, next }`, `next` = `<issuer>/connect/setup/<provider>`. The daemon never raises it (it only carries `dependencies`).
|
|
22
|
+
provider_setup_pending: { type: 'permission_error', status: 403, retryable: false },
|
|
21
23
|
question_pages_off: { type: 'permission_error', status: 403, retryable: false },
|
|
22
24
|
isolated_run: { type: 'permission_error', status: 403, retryable: false },
|
|
23
25
|
provider_version_retired: { type: 'permission_error', status: 403, retryable: false },
|
package/dist/api/index.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export * from './dto/broker-signals.js';
|
|
|
17
17
|
export * from './dto/bash-jobs.js';
|
|
18
18
|
export * from './dto/messages.js';
|
|
19
19
|
export * from './dto/reports.js';
|
|
20
|
+
export * from './dto/structured-requests.js';
|
|
20
21
|
export * from './dto/lifecycle.js';
|
|
21
22
|
export * from './dto/subscriptions.js';
|
|
22
23
|
export * from './dto/focus.js';
|
package/dist/api/index.js
CHANGED
|
@@ -17,6 +17,7 @@ export * from './dto/broker-signals.js';
|
|
|
17
17
|
export * from './dto/bash-jobs.js';
|
|
18
18
|
export * from './dto/messages.js';
|
|
19
19
|
export * from './dto/reports.js';
|
|
20
|
+
export * from './dto/structured-requests.js';
|
|
20
21
|
export * from './dto/lifecycle.js';
|
|
21
22
|
export * from './dto/subscriptions.js';
|
|
22
23
|
export * from './dto/focus.js';
|
|
@@ -18,7 +18,7 @@ export declare const CONNECTION_FAULT_RECOVERY_BODY = "The network connection is
|
|
|
18
18
|
export declare const PROVIDER_FAULT_RECOVERY_BODY = "Your previous turn stopped on a provider fault. Continue from where you left off and retry the work that failed.";
|
|
19
19
|
export type ModelFallbackRecoveryReason = 'credential' | 'not-found';
|
|
20
20
|
/** Format the stop guard's dynamic structured-output mandate. */
|
|
21
|
-
export declare function formatStructuredOutputReprompt(schema: string): string;
|
|
21
|
+
export declare function formatStructuredOutputReprompt(schema: string, requestId: string): string;
|
|
22
22
|
/** Keep model-fallback guidance editable without making it a reader contract. */
|
|
23
23
|
export declare function formatModelFallbackRecovery(previousModel: string, nextModel: string, reason: ModelFallbackRecoveryReason): string;
|
|
24
24
|
export interface GeneratedContextMessageLike {
|
|
@@ -29,11 +29,11 @@ const REVIEW_APPROVAL_OPEN = '<crtr-review-approval>';
|
|
|
29
29
|
const REVIEW_APPROVAL_CLOSE = '</crtr-review-approval>';
|
|
30
30
|
const MODEL_FALLBACK_RECOVERY_OPEN = '<model-fallback-recovery>';
|
|
31
31
|
const MODEL_FALLBACK_RECOVERY_CLOSE = '</model-fallback-recovery>';
|
|
32
|
-
const STRUCTURED_OUTPUT_REPROMPT_PREFIX = 'You must submit a result matching the required schema with `crtr push result` before you can stop, or decline it with `crtr push result --decline "<reason>" --code <token>` when the schema cannot be honestly satisfied. You cannot finish or go dormant any other way while this request is pending.\n\nRequired schema:\n\n```json\n';
|
|
33
32
|
const STRUCTURED_OUTPUT_REPROMPT_SUFFIX = '\n```';
|
|
34
33
|
/** Format the stop guard's dynamic structured-output mandate. */
|
|
35
|
-
export function formatStructuredOutputReprompt(schema) {
|
|
36
|
-
|
|
34
|
+
export function formatStructuredOutputReprompt(schema, requestId) {
|
|
35
|
+
const submit = `crtr push result --request ${requestId}`;
|
|
36
|
+
return `You must submit a result matching the required schema with \`${submit}\` before you can stop, or decline it with \`${submit} --decline "<reason>" --code <token>\` when the schema cannot be honestly satisfied. You cannot finish or go dormant any other way while this request is pending.\n\nRequired schema:\n\n\`\`\`json\n${schema}${STRUCTURED_OUTPUT_REPROMPT_SUFFIX}`;
|
|
37
37
|
}
|
|
38
38
|
/** Keep model-fallback guidance editable without making it a reader contract. */
|
|
39
39
|
export function formatModelFallbackRecovery(previousModel, nextModel, reason) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crouter/api",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.384",
|
|
4
4
|
"description": "Typed crtrd /v1 API contract — DTOs, route builders, the error contract, the CrtrClient, and the command-plugin manifest format. Zero runtime dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/api/index.js",
|