diff --git a/.repository-projection.json b/.repository-projection.json index 1f7f292..4de5269 100644 --- a/.repository-projection.json +++ b/.repository-projection.json @@ -3,11 +3,11 @@ "projection": "deixic-node", "projectionSchemaVersion": 1, "sourceRepository": "dx-corp/mono", - "sourceSha": "274db22a3ad92a0a22c45c0ecbc770f92c9d053d", + "sourceSha": "a971433d12b40d9042b3a64c2c074fa8fc398e69", "destinationRepository": "dx-corp/deixic-node", - "priorProjectedBase": "77f4e5fa7c3c2086d7581e6b5c1af7d137c03d72", - "definitionDigest": "6c8bda5a9e80c50ccdc2d79d85f61b7f2373eb695dcc86f51f6240901cdf3c28", - "toolDigest": "898e8657d9153a2a51d7c283bf83bb3350b5d1e6", - "contentDigest": "28995d4c14f796455f3ca5434951c10c6e1023438bf40a06894a534ba1007085", + "priorProjectedBase": "dbf984fd9e8fa133670a1baecc041d87dd8477b7", + "definitionDigest": "1984dfa11c2bd95dd871179573e2ab3783be7a6af86d9bf3cd0d1a3f10b15b86", + "toolDigest": "ff02edcbb40b0028af10ab01a101e918341f157a", + "contentDigest": "b2599945950a65ab6746aa14b8969fff44f412d4adf77f2d5549f1b8132c5ec9", "publicationEligible": true } diff --git a/sdk/deixic/typescript/README.md b/sdk/deixic/typescript/README.md index c5fdae9..5e9990f 100644 --- a/sdk/deixic/typescript/README.md +++ b/sdk/deixic/typescript/README.md @@ -2,8 +2,7 @@ `@evalops/deixic-sdk` is the supported TypeScript client for applications that submit Deixic tasks, follow durable progress, interrupt work, and approve or -deny requested actions. It exposes that focused contract without publishing -Deixic's browser-only API as an application interface. +deny requested actions. Its top-level client exposes those supported methods. ## Install @@ -45,34 +44,6 @@ and retrieves the final answer linked to that accepted turn, together with its referenced receipts. The lower-level `observeAcceptedTurn` helper remains available for callers that own their streaming policy. -## Compliance assessments - -`deixic.compliance.assess()` evaluates a versioned control against a record -fetched from its owning service under the client's fixed organization and -workspace: - -```ts -const { assessment } = await deixic.compliance.assess({ - profileId: "dex-production-action-assurance/v1", - subjectKind: "tool_execution", - subjectId: "tex_123", -}); -``` - -The response names each requirement, its `ComplianceFindingStatus` value, -a reason code and the owner reference. The first profile tags findings with -the internal `DEX-ACTION-ASSURANCE` control; mapping that control to an -external framework requires a separately reviewed mapping. Denied actions are `NOT_APPLICABLE`; -executions without a confirmed succeeded state are `INDETERMINATE`. It includes a -digest of the exact Tool Execution returned by the owner and declares coverage -of one requested record. This is a live read. To retain a server-owned -snapshot, call `deixic.compliance.record()` with the same subject and an -`idempotencyKey`, then retrieve its `record.id` with `deixic.compliance.get()`. -Repeating the key returns the first accepted snapshot. The current profile reports -the independent Audit receipt as indeterminate because Tool Executor has no -general Audit sink. Do not treat the result as proof of an external state -change or of every action in a time window. - ## Task handles and setup checks `await deixic.tasks.checkSetup({ channelId: "company" })` makes one read @@ -221,3 +192,17 @@ retains the original Connect failure for advanced diagnostics. Node.js 20 or later is supported. The client also works in modern browsers when the application supplies an appropriate authenticated transport. + +## Public protocol boundary + +This package includes only the `deixicpublic.v1.DeixicPublicService` contract +and its standard protobuf dependencies. Read responses expose public thread, +message, event, setup, and receipt projections. Receipt evidence uses public +resource references; service ownership and internal execution records are not +part of this contract. Pagination uses page tokens. + +Existing `deixic.task.v1` checkpoints remain readable, including accepted turn +IDs and decimal-string cursors. Their `channelId` identifies the public thread. +Python message types are available from `deixic.protocol`; TypeScript exports +public message types and schemas from the package root. Existing TypeScript +operating-type names are aliases of these public types. diff --git a/sdk/deixic/typescript/examples/account-brief.mjs b/sdk/deixic/typescript/examples/account-brief.mjs index 3fc93c6..1a36fc9 100755 --- a/sdk/deixic/typescript/examples/account-brief.mjs +++ b/sdk/deixic/typescript/examples/account-brief.mjs @@ -61,7 +61,7 @@ async function main() { writeAccess: check.writeAccess, nextAction: check.nextAction, requirements: check.capabilities.map(item => ({ service: item.service, missingRequirements: item.missingRequirements, - reasonCodes: item.missingRequirementStates.map(reason => reason.reasonCode) })), + accessible: item.accessible })), modelReady: check.selectedModel?.ready ?? null, errorKind: check.error?.kind, requestId: check.error?.requestId, })); @@ -86,13 +86,13 @@ async function main() { else if (["approve", "deny"].includes(action)) { const result = await task.result(); const event = result.event; - if (result.status !== "waiting" || !event || event.requestType !== OperatingThreadRequestType.APPROVAL + if (result.status !== "waiting" || !event || event.requestKind !== OperatingThreadRequestType.APPROVAL || event.requestId !== values.request) { console.log(JSON.stringify({ status: "needs_attention", reason: "approval_request_not_current" })); return 2; } await client.controls.respond({ channelId: task.checkpoint().channelId, turnId: result.turnId, - response: { requestId: event.requestId, callId: event.requestCallId, requestType: event.requestType, + response: { requestId: event.requestId, callId: event.callId, requestKind: event.requestKind, action: action === "approve" ? OperatingThreadResponseAction.APPROVE : OperatingThreadResponseAction.DENY }, idempotencyKey: values["decision-key"], }); @@ -121,15 +121,15 @@ async function main() { } } const receipts = result.status === "completed" ? result.receipts : []; - const actions = receipts.map(item => ({ id: item.id, ownerService: item.ownerService, - objectId: item.objectId, kind: item.kind, lifecycleState: item.lifecycleState, - evidenceRefs: item.evidenceRefs.map(ref => ({ resourceType: ref.resourceType, id: ref.id })) })); - const attention = receipts.some(item => ![ReceiptLifecycleState.SUCCEEDED, ReceiptLifecycleState.VERIFIED].includes(item.lifecycleState)); + const actions = receipts.map(item => ({ id: item.id, ownerService: undefined, + objectId: undefined, kind: item.kind, lifecycleState: item.state, + evidenceRefs: item.evidence.map(ref => ({ resourceType: ref.kind, id: ref.id })) })); + const attention = receipts.some(item => ![ReceiptLifecycleState.SUCCEEDED, ReceiptLifecycleState.VERIFIED].includes(item.state)); console.log(JSON.stringify({ status: result.status, turnId: result.turnId, reason: result.reason, body: result.status === "completed" && !structured ? result.body : undefined, brief, receiptIds: receipts.map(item => item.id), actions, actionStatus: !actions.length ? "not_reported" : attention ? "requires_attention" : "owner_reported_success", - requestId: result.event?.requestId, requestType: result.event?.requestType, errorCode: result.turn?.errorCode, + requestId: result.event?.requestId, requestKind: result.event?.requestKind, errorCode: result.turn?.terminalError?.code, })); return result.status === "completed" && !attention ? 0 : 2; } diff --git a/sdk/deixic/typescript/package.json b/sdk/deixic/typescript/package.json index f249e18..cc6ccad 100644 --- a/sdk/deixic/typescript/package.json +++ b/sdk/deixic/typescript/package.json @@ -29,7 +29,7 @@ "package.json" ], "scripts": { - "build": "node ../../maestro/typescript/scripts/verify-descriptor-sources.mjs && rm -rf dist && tsc -p tsconfig.json", + "build": "rm -rf dist && tsc -p tsconfig.json", "typecheck": "tsc --noEmit", "test": "npm run build && node --test test/*.test.mjs", "check:package": "npm run build && node scripts/check-package-exports.mjs && node scripts/smoke-packed-package.mjs", diff --git a/sdk/deixic/typescript/scripts/smoke-packed-package.mjs b/sdk/deixic/typescript/scripts/smoke-packed-package.mjs index cd33f17..9989a76 100644 --- a/sdk/deixic/typescript/scripts/smoke-packed-package.mjs +++ b/sdk/deixic/typescript/scripts/smoke-packed-package.mjs @@ -16,9 +16,9 @@ try { const names = new Set(result[0].files.map((file) => file.path)); assert(names.has("LICENSE")); assert(names.has("dist/sdk/deixic/typescript/src/index.js")); - assert(names.has("dist/sdk/maestro/typescript/src/client.js")); - assert(names.has("dist/gen/ts/console/v1/console_pb.js")); - assert(names.has("dist/gen/ts/deixic/v1/deixic_pb.js")); + assert(names.has("dist/sdk/deixic/typescript/src/client.js")); + assert(names.has("dist/sdk/deixic/typescript/src/protocol.js")); + assert(![...names].some(name => name.includes("dist/gen/"))); assert(names.has("examples/account-brief.mjs")); assert(names.has("dist/sdk/deixic/typescript/src/tasks.js")); @@ -60,23 +60,23 @@ const client = createDeixicClient({ transport: { async unary(method, signal, timeout, headers, input) { calls += 1; - assert.equal(method.parent.typeName, "deixic.v1.DeixicService"); + assert.equal(method.parent.typeName, "deixicpublic.v1.DeixicPublicService"); assert.equal(headers.get("Authorization"), "Bearer package-test-key"); - assert.equal(input.query.organizationId, "org-package-test"); - assert.equal(input.query.workspaceId, "workspace-package-test"); + assert.equal(input.scope.organizationId, "org-package-test"); + assert.equal(input.scope.workspaceId, "workspace-package-test"); let fields; - if (method.name === "SubmitOperatingMessage") { + if (method.name === "SubmitTask") { assert.equal(input.idempotencyKey, "installed-request"); - fields = { replayCursor: 9007199254740993n, acceptedTurn: { turnId: "installed-turn", sequence: 2n, state: OperatingTurnState.QUEUED } }; - } else if (method.name === "ListOperatingThreadEvents") { + fields = { replayCursor: 9007199254740993n, acceptedTurn: { turnId: "installed-turn", sequence: 2n, state: OperatingTurnState.ACCEPTED } }; + } else if (method.name === "ListEvents") { completed = true; fields = { nextCursor: input.afterCursor }; } else { - assert.equal(method.name, "GetOperatingThread"); - fields = { replayCursor: 9007199254740993n, channel: { id: "channel-package-test" }, - turns: [{ turnId: "installed-turn", sequence: 2n, state: completed ? OperatingTurnState.COMPLETED : OperatingTurnState.QUEUED, + assert.equal(method.name, "GetThread"); + fields = { replayCursor: 9007199254740993n, thread: { id: "channel-package-test" }, + turns: [{ turnId: "installed-turn", sequence: 2n, state: completed ? OperatingTurnState.COMPLETED : OperatingTurnState.ACCEPTED, assistantMessageId: completed ? "answer" : "" }], - messages: completed ? [{ id: "answer", channelId: "channel-package-test", role: "assistant", body: "Installed result" }] : [] }; + messages: completed ? [{ id: "answer", channelId: "channel-package-test", role: 2, body: "Installed result" }] : [] }; } return { message: create(method.output, fields) }; }, diff --git a/sdk/deixic/typescript/src/accepted-turn.ts b/sdk/deixic/typescript/src/accepted-turn.ts new file mode 100644 index 0000000..7f30f37 --- /dev/null +++ b/sdk/deixic/typescript/src/accepted-turn.ts @@ -0,0 +1,468 @@ +import { clone } from "@bufbuild/protobuf"; +import { + OperatingThreadEventKind, + OperatingThreadEventSchema, + type OperatingThreadExecution, + OperatingThreadTurnSchema, + OperatingTurnState, + type OperatingThreadEvent, + type OperatingThreadTurn, + type SubmitOperatingMessageResponse, +} from "./protocol.js"; + +import type { PublicClient } from "./client.js"; +import { PublicError, asPublicError } from "./errors.js"; + +const DEFAULT_MAX_BACKFILL_PAGES = 10; +const MAX_BACKFILL_PAGES = 50; +const MAX_WATCH_PAGES = 100; +const MAX_OPERATING_CURSOR = 9_223_372_036_854_775_807n; + +/** + * Stable acceptance coordinates for one Platform-owned turn. A prior result + * supplies this shape when a caller resumes observation from its cursor. + */ +export interface PublicAcceptedTurnAcceptance { + acceptedTurn?: OperatingThreadTurn; + replayCursor: bigint; +} + +/** One caller-bounded WatchOperatingThread segment. */ +export interface PublicAcceptedTurnWatchOptions { + /** Number of stream pages to process before observation returns unfinished. */ + maxPages: number; +} + +export interface PublicObserveAcceptedTurnInput { + channelId: string; + /** + * A SubmitOperatingMessage response or a prior result's acceptedTurn and + * replayCursor. It identifies the accepted owner turn without resending it. + */ + acceptance: PublicAcceptedTurnAcceptance + | Pick; + /** Maximum ListOperatingThreadEvents pages before observation stops. */ + maxBackfillPages?: number; + /** Optional one-shot watch. Reconnect policy remains with the caller. */ + watch?: PublicAcceptedTurnWatchOptions; + /** Receives each new exact-turn event in cursor order. */ + onEvent?: (event: Readonly) => void | Promise; + /** Stops observation only; this helper never interrupts or resends a turn. */ + signal?: AbortSignal; +} + +interface PublicAcceptedTurnResultBase { + /** Detached identity snapshot for a later observation call. */ + acceptedTurn: OperatingThreadTurn; + /** Last fully processed durable event cursor, preserved as bigint. */ + replayCursor: bigint; + /** Detached matching owner snapshot, when Platform supplied one. */ + turn?: OperatingThreadTurn; + /** Detached matching event that established the returned state. */ + event?: OperatingThreadEvent; +} + +export type PublicAcceptedTurnUnfinishedReason = + | "backfill_limit" + | "backfill_error" + | "watch_not_requested" + | "watch_eof" + | "watch_page_limit" + | "watch_error" + | "reset_required" + | "reset_missing_turn" + | "cancelled"; + +/** + * Result for a single accepted durable turn. `responded` remains separate + * from `completed` because Platform exposes those owner states separately. + */ +export type PublicAcceptedTurnResult = + | (PublicAcceptedTurnResultBase & { status: "responded" }) + | (PublicAcceptedTurnResultBase & { status: "completed" }) + | (PublicAcceptedTurnResultBase & { status: "failed" }) + | (PublicAcceptedTurnResultBase & { status: "interrupted" }) + | (PublicAcceptedTurnResultBase & { status: "waiting" }) + | (PublicAcceptedTurnResultBase & { + status: "unfinished"; + reason: PublicAcceptedTurnUnfinishedReason; + error?: PublicError; + }); + +/** + * Observe one already-accepted Platform turn through the durable event API. + * The helper uses only the tenant scope already fixed on `client`. + */ +export async function observePublicAcceptedTurn( + client: PublicClient, + input: PublicObserveAcceptedTurnInput, +): Promise { + const signal = input.signal; + const channelId = requiredString(input.channelId, "channelId"); + const acceptance = input.acceptance; + if (!acceptance || typeof acceptance !== "object") { + throw validationError("acceptance is required"); + } + const sourceTurn = acceptance.acceptedTurn; + if (!sourceTurn) throw validationError("acceptance.acceptedTurn is required"); + + const acceptedTurn = clone(OperatingThreadTurnSchema, sourceTurn); + const turnId = requiredString(acceptedTurn.turnId, "acceptance.acceptedTurn.turnId"); + if (acceptedTurn.turnId !== turnId) { + throw validationError("acceptance.acceptedTurn.turnId must not have surrounding whitespace"); + } + const sequence = inputCursor(acceptedTurn.sequence, "acceptance.acceptedTurn.sequence", true); + inputCursor( + acceptedTurn.lastCursor, + "acceptance.acceptedTurn.lastCursor", + ); + // This is the caller's consumed watermark. A newer turn snapshot cannot + // advance it, because doing so would skip unseen event history on resume. + let replayCursor = inputCursor(acceptance.replayCursor, "acceptance.replayCursor"); + const maxBackfillPages = boundedPageCount( + input.maxBackfillPages, + DEFAULT_MAX_BACKFILL_PAGES, + MAX_BACKFILL_PAGES, + "maxBackfillPages", + ); + const maxWatchPages = input.watch === undefined + ? undefined + : boundedPageCount(input.watch.maxPages, undefined, MAX_WATCH_PAGES, "watch.maxPages"); + const onEvent = input.onEvent; + if (onEvent !== undefined && typeof onEvent !== "function") { + throw validationError("onEvent must be a function"); + } + + let latestTurn: OperatingThreadTurn | undefined; + let latestEvent: OperatingThreadEvent | undefined; + const seenEventIds = new Map(); + const seenEventCursors = new Map(); + + const base = (): PublicAcceptedTurnResultBase => ({ + acceptedTurn: clone(OperatingThreadTurnSchema, acceptedTurn), + replayCursor, + ...(latestTurn ? { turn: clone(OperatingThreadTurnSchema, latestTurn) } : {}), + ...(latestEvent ? { event: clone(OperatingThreadEventSchema, latestEvent) } : {}), + }); + const unfinished = ( + reason: PublicAcceptedTurnUnfinishedReason, + error?: PublicError, + ): PublicAcceptedTurnResult => ({ + ...base(), + status: "unfinished", + reason, + ...(error ? { error } : {}), + }); + const cancelled = (): PublicAcceptedTurnResult => unfinished("cancelled"); + + if (signal?.aborted) return cancelled(); + + // A detached terminal owner snapshot is terminal proof for this exact turn. + // WAITING always backfills so the matching event retains its request + // identity for the caller. + const acceptedOutcome = outcomeForTurn(acceptedTurn); + if (acceptedOutcome && acceptedOutcome !== "waiting") { + latestTurn = clone(OperatingThreadTurnSchema, acceptedTurn); + return { ...base(), status: acceptedOutcome }; + } + const processPage = async (page: ObservationPage): Promise => { + const pageStartCursor = replayCursor; + const nextCursor = responseCursor(page.nextCursor, "response.nextCursor"); + if (nextCursor < pageStartCursor) { + throw protocolError("response.nextCursor regressed from the current replay cursor"); + } + if (signal?.aborted) return cancelled(); + + if (page.resetRequired) { + // A reset snapshot is authoritative. Do not apply the page's event list + // or use page.nextCursor or a turn snapshot as the replacement cursor. + latestEvent = undefined; + latestTurn = undefined; + seenEventIds.clear(); + seenEventCursors.clear(); + if (!page.snapshot) { + throw protocolError("response.threadExecution is required when resetRequired is true"); + } + const resetCursor = responseCursor( + page.snapshot.replayCursor, + "response.threadExecution.replayCursor", + ); + if (resetCursor < pageStartCursor) { + throw protocolError("response.threadExecution.replayCursor regressed from the current replay cursor"); + } + // A reset cursor comes from the authoritative owner execution record, + // not from a turn snapshot. It replaces the caller's old history. + replayCursor = resetCursor; + const snapshotTurn = page.snapshotTurns.find((candidate) => ( + candidate.turnId === turnId && candidate.sequence === sequence + )); + if (!snapshotTurn) return unfinished("reset_missing_turn"); + const copiedTurn = clone(OperatingThreadTurnSchema, snapshotTurn); + responseCursor(copiedTurn.lastCursor, "response.snapshotTurns.lastCursor"); + latestTurn = copiedTurn; + const snapshotOutcome = outcomeForTurn(copiedTurn); + if (snapshotOutcome) return { ...base(), status: snapshotOutcome }; + return unfinished("reset_required"); + } + + const records = page.events.map((source, index) => { + const event = clone(OperatingThreadEventSchema, source); + const cursor = responseCursor(event.cursor, "response.events.cursor", true); + return { cursor, event, identity: eventIdentity(event, cursor), index }; + }); + // Owner list/watch set next_cursor to the last returned event, or the + // request after_cursor when the page is empty. A higher cursor would skip + // undelivered events on the next afterCursor read. + const expectedNextCursor = records.reduce( + (highest, record) => record.cursor > highest ? record.cursor : highest, + pageStartCursor, + ); + if (nextCursor !== expectedNextCursor) { + throw protocolError("response.nextCursor did not match the page event watermark"); + } + + const pageCursorIdentities = new Map(); + for (const record of records) { + const existing = pageCursorIdentities.get(record.cursor); + if (existing !== undefined && existing !== record.identity) { + throw protocolError("response.events contained different events at the same cursor"); + } + pageCursorIdentities.set(record.cursor, record.identity); + } + + const matchingEvents = records + .filter((record) => record.event.turnId === turnId) + .sort((left, right) => ( + left.cursor === right.cursor ? left.index - right.index : left.cursor < right.cursor ? -1 : 1 + )); + let latestTerminalEvent: OperatingThreadEvent | undefined; + let latestWaitingEvent: OperatingThreadEvent | undefined; + let waiting = false; + + for (const record of matchingEvents) { + if (record.cursor <= pageStartCursor) continue; + + const eventId = record.event.id.trim(); + const previousAtCursor = seenEventCursors.get(record.cursor); + if (previousAtCursor !== undefined) { + if (previousAtCursor !== record.identity) { + throw protocolError("response.events reused a cursor for different accepted-turn events"); + } + continue; + } + if (eventId) { + const previousCursor = seenEventIds.get(eventId); + if (previousCursor !== undefined) { + if (previousCursor !== record.cursor) { + throw protocolError("response.events reused an eventId at a different cursor"); + } + continue; + } + seenEventIds.set(eventId, record.cursor); + } + seenEventCursors.set(record.cursor, record.identity); + + // Classify from this private clone before invoking application code. The + // callback receives another detached object and cannot forge a result. + latestEvent = record.event; + const terminal = terminalOutcomeForEvent(record.event); + if (terminal) { + latestTerminalEvent = record.event; + latestWaitingEvent = undefined; + waiting = false; + } else if (!latestTerminalEvent) { + if (isWaitingEvent(record.event)) { + latestWaitingEvent = record.event; + waiting = true; + } else if (clearsWaitingEvent(record.event)) { + latestWaitingEvent = undefined; + waiting = false; + } + } + try { + await onEvent?.(Object.freeze(clone(OperatingThreadEventSchema, record.event))); + } catch (error) { + throw new ObservationCallbackError(error); + } + if (signal?.aborted) return cancelled(); + } + + replayCursor = nextCursor; + if (latestTerminalEvent) { + latestEvent = latestTerminalEvent; + const terminalOutcome = terminalOutcomeForEvent(latestTerminalEvent); + if (!terminalOutcome) throw protocolError("accepted-turn terminal event had no terminal outcome"); + return { ...base(), status: terminalOutcome }; + } + if (waiting && latestWaitingEvent) { + latestEvent = latestWaitingEvent; + return { ...base(), status: "waiting" }; + } + return undefined; + }; + + let hasMore = true; + for (let pageNumber = 0; pageNumber < maxBackfillPages && hasMore; pageNumber += 1) { + if (signal?.aborted) return cancelled(); + try { + const page = await client.events.list({ channelId, afterCursor: replayCursor, signal }); + const result = await processPage(page); + if (result) return result; + hasMore = page.hasMore; + } catch (error) { + if (signal?.aborted) return cancelled(); + rethrowObservationError(error); + return unfinished("backfill_error", asPublicError(error)); + } + } + + if (hasMore) return unfinished("backfill_limit"); + if (maxWatchPages === undefined) return unfinished("watch_not_requested"); + if (signal?.aborted) return cancelled(); + + let pageCount = 0; + try { + for await (const page of client.events.watch({ channelId, afterCursor: replayCursor, signal })) { + if (signal?.aborted) return cancelled(); + const result = await processPage(page); + if (result) return result; + pageCount += 1; + if (pageCount >= maxWatchPages) return unfinished("watch_page_limit"); + } + } catch (error) { + if (signal?.aborted) return cancelled(); + rethrowObservationError(error); + return unfinished("watch_error", asPublicError(error)); + } + + return unfinished("watch_eof"); +} + +type ObservationPage = { + events: readonly OperatingThreadEvent[]; + nextCursor: bigint; + resetRequired: boolean; + snapshot?: OperatingThreadExecution; + snapshotTurns: readonly OperatingThreadTurn[]; +}; + +type TerminalOutcome = "responded" | "completed" | "failed" | "interrupted"; + +function outcomeForTurn(turn: OperatingThreadTurn): TerminalOutcome | "waiting" | undefined { + switch (turn.state) { + case OperatingTurnState.RESPONDED: + return "responded"; + case OperatingTurnState.COMPLETED: + return "completed"; + case OperatingTurnState.FAILED: + return "failed"; + case OperatingTurnState.INTERRUPTED: + return "interrupted"; + case OperatingTurnState.WAITING: + return "waiting"; + default: + return undefined; + } +} + +function terminalOutcomeForEvent(event: OperatingThreadEvent | undefined): TerminalOutcome | undefined { + switch (event?.kind) { + case OperatingThreadEventKind.TURN_COMPLETED: + return "completed"; + case OperatingThreadEventKind.TURN_FAILED: + return "failed"; + case OperatingThreadEventKind.TURN_INTERRUPTED: + return "interrupted"; + default: + return undefined; + } +} + +function isWaitingEvent(event: OperatingThreadEvent): boolean { + return event.kind === OperatingThreadEventKind.APPROVAL_REQUIRED + || event.kind === OperatingThreadEventKind.INPUT_REQUIRED + || event.kind === OperatingThreadEventKind.CLIENT_TOOL_REQUIRED + || event.kind === OperatingThreadEventKind.EXTERNAL_RETRY_REQUIRED; +} + +function clearsWaitingEvent(event: OperatingThreadEvent): boolean { + return event.kind === OperatingThreadEventKind.TURN_ACCEPTED + || event.kind === OperatingThreadEventKind.TURN_STARTED; +} + +function eventIdentity(event: OperatingThreadEvent, cursor: bigint): string { + const eventId = event.id.trim(); + if (eventId) return `id:${eventId}`; + return [ + "fallback", + cursor.toString(10), + event.turnId, + String(event.kind), + event.requestId, + event.callId, + ].join("\u0000"); +} + +function boundedPageCount( + value: number | undefined, + defaultValue: number | undefined, + maxValue: number, + field: string, +): number { + const resolved = value ?? defaultValue; + if (resolved === undefined || !Number.isInteger(resolved) || resolved < 1 || resolved > maxValue) { + throw validationError(`${field} must be an integer from 1 to ${maxValue}`); + } + return resolved; +} + +function requiredString(value: string, field: string): string { + const normalized = typeof value === "string" ? value.trim() : ""; + if (!normalized) throw validationError(`${field} is required`); + return normalized; +} + +function inputCursor(value: bigint, field: string, positive = false): bigint { + if (typeof value !== "bigint" || value < (positive ? 1n : 0n) || value > MAX_OPERATING_CURSOR) { + throw validationError(`${field} must be a ${positive ? "positive" : "non-negative"} int64 bigint`); + } + return value; +} + +function responseCursor(value: bigint, field: string, positive = false): bigint { + if (typeof value !== "bigint" || value < (positive ? 1n : 0n) || value > MAX_OPERATING_CURSOR) { + throw protocolError(`${field} must be a ${positive ? "positive" : "non-negative"} int64 bigint`); + } + return value; +} + +function validationError(message: string): PublicError { + return new PublicError({ message, kind: "validation", status: 400 }); +} + +function protocolError(message: string): ObservationProtocolError { + return new ObservationProtocolError(new PublicError({ + message, + kind: "protocol", + status: 502, + })); +} + +function rethrowObservationError(error: unknown): void { + if (error instanceof ObservationProtocolError) throw error.productError; + if (error instanceof ObservationCallbackError) throw error.callbackError; +} + +class ObservationProtocolError extends Error { + constructor(readonly productError: PublicError) { + super(productError.message, { cause: productError }); + this.name = "ObservationProtocolError"; + } +} + +class ObservationCallbackError extends Error { + constructor(readonly callbackError: unknown) { + super("accepted-turn observation callback failed", { cause: callbackError }); + this.name = "ObservationCallbackError"; + } +} diff --git a/sdk/deixic/typescript/src/app-context.ts b/sdk/deixic/typescript/src/app-context.ts new file mode 100644 index 0000000..6849518 --- /dev/null +++ b/sdk/deixic/typescript/src/app-context.ts @@ -0,0 +1,101 @@ +/** The only SDK request header that may carry product routing context. */ +export const DEIXIC_PUBLIC_APP_CONTEXT_HEADER = "X-EvalOps-App-Context"; + +/** Matches the existing Operating Chat header budget. */ +export const DEIXIC_PUBLIC_APP_CONTEXT_MAX_HEADER_CHARS = 6000; + +/** + * Encodes bounded, redacted product context for one submitted message. + * + * This context is intentionally kept out of the durable protobuf body. It can + * guide request routing but does not become a user message or a completion + * record. + */ +export function encodePublicAppContextHeader(value: unknown): string | undefined { + const normalized = normalizeForHeader(value); + if (normalized === undefined) return undefined; + + const encoded = encodedNormalizedContext(normalized); + if (encoded.length <= DEIXIC_PUBLIC_APP_CONTEXT_MAX_HEADER_CHARS) return encoded; + + return encodeURIComponent(JSON.stringify({ + schema: "dex.app_context.v1", + truncated: true, + reason: "encoded_context_exceeded_header_budget", + })); +} + +/** + * Returns the encoded length before the oversized-header fallback is applied. + * Product UIs use this to decide whether to compact context before submit. + */ +export function encodedPublicAppContextHeaderLength(value: unknown): number { + const normalized = normalizeForHeader(value); + return normalized === undefined ? 0 : encodedNormalizedContext(normalized).length; +} + +function encodedNormalizedContext(normalized: unknown): string { + return encodeURIComponent(JSON.stringify(normalized)); +} + +function normalizeForHeader(value: unknown): unknown { + if (value === null || value === undefined) return undefined; + if (typeof value === "string") return sanitizeString(value); + if (typeof value === "number") return Number.isFinite(value) ? value : undefined; + if (typeof value === "boolean") return value; + if (Array.isArray(value)) { + return value + .slice(0, 25) + .map((item) => normalizeForHeader(item)) + .filter((item) => item !== undefined); + } + if (typeof value === "object") { + const out: Record = {}; + for (const [key, item] of Object.entries(value as Record).slice(0, 50)) { + const cleanKey = sanitizeKey(key); + if (!cleanKey || sensitiveKey(cleanKey)) continue; + const normalizedItem = normalizeForHeader(item); + if (normalizedItem !== undefined) out[cleanKey] = normalizedItem; + } + return Object.keys(out).length > 0 ? out : undefined; + } + return undefined; +} + +function sanitizeKey(value: string): string { + return value.replace(/[^a-zA-Z0-9_.-]/g, "_").slice(0, 80); +} + +function sanitizeString(value: string): string { + const normalized = value + .replace(/[\u0000-\u001f\u007f]/g, " ") + .replace(/\s+/g, " ") + .trim(); + return redactSensitiveString(normalized).slice(0, 300); +} + +function redactSensitiveString(value: string): string { + return value + .replace( + /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z0-9 ]*PRIVATE KEY-----/gi, + "[REDACTED]", + ) + .replace( + /("(?:api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|password|passwd|private[_-]?key|authorization)"\s*:\s*)"(?:[^"\\]|\\.)*"/gi, + "$1\"[REDACTED]\"", + ) + .replace(/\bBearer[ \t]+[A-Za-z0-9._~+/=-]{8,}/gi, "Bearer [REDACTED]") + .replace( + /\b([A-Z][A-Z0-9_]*(?:API_?KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIALS?|PRIVATE_?KEY)[A-Z0-9_]*)\s*([=:])\s*(?:"[^"\r\n]*"|'[^'\r\n]*'|[^\s,;]+)/gi, + "$1$2[REDACTED]", + ) + .replace(/([a-z][a-z0-9+.-]*:\/\/)[^/@\s:]+:[^/@\s]+@/gi, "$1[REDACTED]@") + .replace( + /\b(?:sk-[A-Za-z0-9_-]{16,}|sk_live_[A-Za-z0-9]{16,}|github_pat_[A-Za-z0-9_]{20,}|gh[pousr]_[A-Za-z0-9_]{20,}|xox[baprs]-[A-Za-z0-9-]{10,}|AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35}|eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,})\b/g, + "[REDACTED]", + ); +} + +function sensitiveKey(key: string): boolean { + return /(^|[_.-])(authorization|bearer|cookie|token|secret|password|credential|code|state|session)($|[_.-])/i.test(key); +} diff --git a/sdk/deixic/typescript/src/client.ts b/sdk/deixic/typescript/src/client.ts new file mode 100644 index 0000000..b7a6f7b --- /dev/null +++ b/sdk/deixic/typescript/src/client.ts @@ -0,0 +1,713 @@ +import { + clone, + create, + type DescMessage, + type MessageInitShape, + type MessageShape, +} from "@bufbuild/protobuf"; +import { createClient, type Transport } from "@connectrpc/connect"; +import { createConnectTransport } from "@connectrpc/connect-web"; +import { + CodingAcceptanceContractSchema, + ConsoleQuerySchema, + GetOperatingReceiptRequestSchema, + GetOperatingReceiptResponseSchema, + GetOperatingThreadRequestSchema, + GetOperatingThreadResponseSchema, + InterruptOperatingThreadRequestSchema, + InterruptOperatingThreadResponseSchema, + ListOperatingThreadEventsRequestSchema, + ListOperatingThreadEventsResponseSchema, + OperatingModelSelectionSchema, + OperatingReceiptActionSchema, + OperatingThreadResponseSchema, + ResolveOperatingReceiptActionRequestSchema, + ResolveOperatingReceiptActionResponseSchema, + RespondOperatingThreadRequestSchema, + RespondOperatingThreadResponseSchema, + SubmitOperatingMessageRequestSchema, + SubmitOperatingMessageResponseSchema, + WatchOperatingThreadRequestSchema, + WatchOperatingThreadResponseSchema, + type GetOperatingReceiptResponse, + type GetOperatingThreadResponse, + type InterruptOperatingThreadResponse, + type ListOperatingThreadEventsResponse, + type OperatingReceiptAction, + type ResolveOperatingReceiptActionResponse, + type RespondOperatingThreadResponse, + type SubmitOperatingMessageResponse, + type WatchOperatingThreadResponse, +} from "./protocol.js"; +import { DeixicPublicService as DeixicService } from "./protocol.js"; + +import { + DEIXIC_PUBLIC_APP_CONTEXT_HEADER, + encodePublicAppContextHeader, +} from "./app-context.js"; +import { + INTERNAL_DEIXIC_PUBLIC_HTTP_STATUS_HEADER, + PublicError, + asPublicError, + isUnauthenticated, +} from "./errors.js"; + +const DEFAULT_THREAD_LIMIT = 100; +const DEFAULT_EVENT_LIMIT = 200; +const MAX_EVENT_LIMIT = 200; +const MAX_OPERATING_CURSOR = 9_223_372_036_854_775_807n; +const MAX_INT32 = 2_147_483_647; + +/** The immutable tenant boundary used for every public SDK call. */ +export interface PublicScope { + organizationId: string; + workspaceId: string; +} + +/** + * Credential metadata is optional so a same-origin BFF can rely on its cookie + * session. If supplied, declared tenant or subject metadata is checked before + * every request and cannot change during a refresh. + */ +export interface PublicCredential { + accessToken?: string; + tokenType?: string; + subject?: string; + organizationId?: string; + workspaceId?: string; + scopes?: string | readonly string[]; +} + +export interface PublicAuth { + getCredential?: () => MaybePromise; + refreshCredential?: ( + current: PublicCredential | null, + ) => MaybePromise; + /** + * Required for a 401 replay when credentials do not carry a stable subject. + * The callback must compare trusted session identity, not only tenant scope. + */ + verifyRefreshIdentity?: ( + current: PublicCredential, + refreshed: PublicCredential, + ) => MaybePromise; +} + +export interface PublicClientOptions { + /** Platform API base URL. Empty uses the same-origin BFF. */ + baseUrl?: string; + scope: PublicScope; + auth?: PublicAuth; + fetch?: typeof globalThis.fetch; + /** Test or server adapter escape hatch; product calls remain scope-bound. */ + transport?: Transport; +} + +export interface PublicGetThreadInput { + channelId: string; + /** Defaults to Platform's current 100-message operating snapshot window. */ + limit?: number; + /** Only zero is accepted; use pageToken to request older messages. */ + offset?: number; + pageToken?: string; + signal?: AbortSignal; +} + +export interface PublicListThreadEventsInput { + channelId: string; + afterCursor: bigint; + limit?: number; + signal?: AbortSignal; +} + +export interface PublicWatchThreadInput { + channelId: string; + afterCursor: bigint; + signal?: AbortSignal; +} + +export interface PublicSendMessageInput { + channelId: string; + body: string; + /** Caller-owned key. The SDK never creates or replaces it. */ + idempotencyKey: string; + continuationTaskId?: string; + referenceTaskIds?: string[]; + modelSelection?: MessageInitShape; + codingAcceptance?: MessageInitShape; + projectResourceId?: string; + /** Bounded, redacted routing context sent only in X-EvalOps-App-Context. */ + appContext?: unknown; + signal?: AbortSignal; +} + +export interface PublicRespondToThreadInput { + channelId: string; + turnId: string; + /** Must echo the current owner-issued request identity. */ + response: MessageInitShape; + /** Caller-owned key. It is copied into the embedded response if absent. */ + idempotencyKey: string; + signal?: AbortSignal; +} + +export interface PublicInterruptThreadInput { + channelId: string; + turnId?: string; + idempotencyKey: string; + reason?: string; + signal?: AbortSignal; +} + +export interface PublicGetReceiptInput { + channelId: string; + receiptId: string; + signal?: AbortSignal; +} + +export interface PublicResolveReceiptInput { + receiptId: string; + /** Exact action object returned in receipt.allowedActions. */ + action: OperatingReceiptAction; + idempotencyKey: string; + signal?: AbortSignal; +} + +/** + * Typed facade for the durable Platform-owned operating-thread contract. + * Responses are generated protobuf objects; 64-bit cursors remain bigint. + */ +export interface PublicClient { + readonly scope: Readonly; + threads: { + get(input: PublicGetThreadInput): Promise; + }; + events: { + list(input: PublicListThreadEventsInput): Promise; + /** + * One bounded server stream. The caller owns reconnect and backoff policy. + * Resume with the last returned nextCursor; replace its projection when + * resetRequired is true instead of appending the page's snapshotTurns. + */ + watch(input: PublicWatchThreadInput): AsyncIterable; + }; + messages: { + send(input: PublicSendMessageInput): Promise; + }; + controls: { + respond(input: PublicRespondToThreadInput): Promise; + interrupt(input: PublicInterruptThreadInput): Promise; + }; + receipts: { + get(input: PublicGetReceiptInput): Promise; + resolve(input: PublicResolveReceiptInput): Promise; + }; +} + +/** Build a scope-bound public SDK client over Platform's Deixic service. */ +export function createPublicClient(options: PublicClientOptions): PublicClient { + const scope = normalizeScope(options.scope); + const auth = options.auth; + const client = createClient(DeixicService, createTransport(options)); + const identity = new CredentialIdentity(scope); + + function fixedScope() { + return create(ConsoleQuerySchema, { + organizationId: scope.organizationId, + workspaceId: scope.workspaceId, + }); + } + + async function credential(): Promise { + try { + const resolved = await auth?.getCredential?.(); + return identity.check(snapshotCredential(resolved ?? null)); + } catch (error) { + throw asPublicError(error); + } + } + + async function refreshed( + current: PublicCredential | null, + ): Promise { + if (!auth?.refreshCredential) return null; + try { + // Retain a detached proof of what authorized the first request. The + // provider gets its own mutable copy, so it cannot alter that proof + // between a 401 and a replay decision. + const proof = snapshotCredential(current); + const next = await auth.refreshCredential(copyCredential(proof)); + // A refresh provider can decline to produce a credential. This is not an + // ambient-cookie fallback: the SDK performs no replay and lets the + // original authentication error retain its Platform metadata. A later + // regular getCredential() call still rejects a disappeared explicit + // credential through CredentialIdentity. + if (!next) return null; + const refreshedCredential = snapshotCredential(next); + if (!refreshedCredential) return null; + // Validate without changing the accepted identity. A failed session + // verifier must not poison later requests with rejected subject/scope data. + identity.validate(refreshedCredential); + await verifyRefreshIdentity(proof, refreshedCredential); + return identity.check(refreshedCredential); + } catch (error) { + throw asPublicError(error); + } + } + + async function verifyRefreshIdentity( + current: PublicCredential | null, + refreshedCredential: PublicCredential, + ): Promise { + const currentSubject = current?.subject?.trim(); + const refreshedSubject = refreshedCredential.subject?.trim(); + if (currentSubject && refreshedSubject === currentSubject) return; + + if (current && auth?.verifyRefreshIdentity + && await auth.verifyRefreshIdentity( + copyCredential(current), + copyCredential(refreshedCredential), + )) { + return; + } + + throw credentialError( + "credential refresh needs the same stable subject or verified session identity before replay", + ); + } + + function headers(current: PublicCredential | null, appContextHeader?: string): Headers { + const requestHeaders = new Headers({ + Accept: "application/proto", + "X-Organization-ID": scope.organizationId, + "X-Workspace-ID": scope.workspaceId, + }); + + const token = current?.accessToken?.trim(); + if (token) requestHeaders.set("Authorization", `${current?.tokenType?.trim() || "Bearer"} ${token}`); + + if (appContextHeader) requestHeaders.set(DEIXIC_PUBLIC_APP_CONTEXT_HEADER, appContextHeader); + return requestHeaders; + } + + async function unary( + operation: (requestHeaders: Headers) => Promise, + appContext?: unknown, + ): Promise { + // Retain exactly the same bounded/redacted context across the one allowed + // authentication retry, even if a caller mutates its source object later. + const appContextHeader = encodePublicAppContextHeader(appContext); + const current = await credential(); + try { + return await operation(headers(current, appContextHeader)); + } catch (error) { + // Platform authenticates before protobuf decode and effect admission. A + // single retry is therefore limited to an authentication challenge; all + // durable mutations still retain their caller-owned idempotency key. + if (!isUnauthenticated(error) || !auth?.refreshCredential) { + throw asPublicError(error); + } + + const next = await refreshed(current); + if (!next) throw asPublicError(error); + try { + return await operation(headers(next, appContextHeader)); + } catch (retryError) { + throw asPublicError(retryError); + } + } + } + + async function* watch(input: PublicWatchThreadInput): AsyncGenerator { + const request = snapshotRequest(WatchOperatingThreadRequestSchema, { + scope: fixedScope(), + threadId: required(input.channelId, "channelId"), + afterCursor: cursor(input.afterCursor, "afterCursor"), + }); + const current = await credential(); + let yielded = false; + let initialAuthenticationError: unknown; + + try { + for await (const page of client.watchEvents(request, { + headers: headers(current), + signal: input.signal, + })) { + yielded = true; + yield page; + } + return; + } catch (error) { + // A stream that has started is never resumed by the SDK. The caller knows + // its projection/cursor and chooses whether, when, and how to reconnect. + if (yielded || !isUnauthenticated(error) || !auth?.refreshCredential) { + throw asPublicError(error); + } + initialAuthenticationError = error; + } + + const next = await refreshed(current); + if (!next) throw asPublicError(initialAuthenticationError); + + try { + for await (const page of client.watchEvents(request, { + headers: headers(next), + signal: input.signal, + })) { + yield page; + } + } catch (error) { + throw asPublicError(error); + } + } + + return { + scope, + threads: { + get(input) { + const limit = readLimit(input.limit); + const offset = readOffset(input.offset) ?? 0; + if (offset !== 0) throw validationError("Use pageToken for public thread pagination"); + const request = snapshotRequest(GetOperatingThreadRequestSchema, { + scope: fixedScope(), + threadId: required(input.channelId, "channelId"), + limit, + pageToken: input.pageToken ?? "", + }); + return unary((requestHeaders) => client.getThread(request, { + headers: requestHeaders, + signal: input.signal, + })); + }, + }, + events: { + list(input) { + const limit = eventLimit(input.limit); + const request = snapshotRequest(ListOperatingThreadEventsRequestSchema, { + scope: fixedScope(), + threadId: required(input.channelId, "channelId"), + afterCursor: cursor(input.afterCursor, "afterCursor"), + limit, + }); + return unary((requestHeaders) => client.listEvents(request, { + headers: requestHeaders, + signal: input.signal, + })); + }, + watch, + }, + messages: { + send(input) { + const idempotencyKey = required(input.idempotencyKey, "idempotencyKey"); + const request = snapshotRequest(SubmitOperatingMessageRequestSchema, { + scope: fixedScope(), + threadId: required(input.channelId, "channelId"), + body: input.body, + idempotencyKey, + continuationTaskId: input.continuationTaskId ?? "", + referenceTaskIds: input.referenceTaskIds ?? [], + modelSelection: input.modelSelection, + codingContract: input.codingAcceptance, + projectResourceId: input.projectResourceId, + }); + return unary((requestHeaders) => client.submitTask(request, { + headers: requestHeaders, + signal: input.signal, + }), input.appContext); + }, + }, + controls: { + respond(input) { + const idempotencyKey = required(input.idempotencyKey, "idempotencyKey"); + const responseKey = typeof input.response.idempotencyKey === "string" + ? input.response.idempotencyKey.trim() + : ""; + if (responseKey && responseKey !== idempotencyKey) { + throw validationError("response.idempotencyKey must match idempotencyKey"); + } + const request = snapshotRequest(RespondOperatingThreadRequestSchema, { + scope: fixedScope(), + threadId: required(input.channelId, "channelId"), + turnId: required(input.turnId, "turnId"), + requestId: input.response.requestId, + requestKind: input.response.requestKind, + callId: input.response.callId, + action: input.response.action, + text: input.response.text, + isError: input.response.isError, + idempotencyKey, + }); + return unary((requestHeaders) => client.respondToRequest(request, { + headers: requestHeaders, + signal: input.signal, + })); + }, + interrupt(input) { + const request = snapshotRequest(InterruptOperatingThreadRequestSchema, { + scope: fixedScope(), + threadId: required(input.channelId, "channelId"), + turnId: input.turnId ?? "", + idempotencyKey: required(input.idempotencyKey, "idempotencyKey"), + reason: input.reason ?? "", + }); + return unary((requestHeaders) => client.interruptTask(request, { + headers: requestHeaders, + signal: input.signal, + })); + }, + }, + receipts: { + get(input) { + const request = snapshotRequest(GetOperatingReceiptRequestSchema, { + scope: fixedScope(), + threadId: required(input.channelId, "channelId"), + receiptId: required(input.receiptId, "receiptId"), + }); + return unary((requestHeaders) => client.getReceipt(request, { + headers: requestHeaders, + signal: input.signal, + })); + }, + resolve(input) { + if (!input.action) throw validationError("action is required"); + const request = snapshotRequest(ResolveOperatingReceiptActionRequestSchema, { + scope: fixedScope(), + receiptId: required(input.receiptId, "receiptId"), + actionId: required(input.action.id, "action.id"), + idempotencyKey: required(input.idempotencyKey, "idempotencyKey"), + }); + return unary((requestHeaders) => client.resolveReceiptAction(request, { + headers: requestHeaders, + signal: input.signal, + })); + }, + }, + }; +} + +function createTransport(options: PublicClientOptions): Transport { + if (options.transport) return options.transport; + const fetchImpl = options.fetch ?? globalThis.fetch; + if (!fetchImpl) { + throw new PublicError({ + message: "Deixic SDK requires fetch or a Connect transport", + kind: "transport", + }); + } + return createConnectTransport({ + baseUrl: trimTrailingSlash(options.baseUrl ?? ""), + useBinaryFormat: true, + fetch: async (input, init) => preservePlatformHttpStatus(await fetchImpl(input, { + ...init, + credentials: init?.credentials ?? "include", + })), + }); +} + +/** + * Connect preserves response headers for a non-Connect error body but reports + * Code.Unknown. Retain a bounded raw HTTP error status in private metadata so + * the facade can preserve Platform's existing status/code error shape. + */ +function preservePlatformHttpStatus(response: Response): Response { + const preserveStatus = Number.isInteger(response.status) + && response.status >= 400 + && response.status <= 599; + const hasInjectedHeader = response.headers.has(INTERNAL_DEIXIC_PUBLIC_HTTP_STATUS_HEADER); + if (!preserveStatus && !hasInjectedHeader) { + return response; + } + const headers = new Headers(response.headers); + // Do not trust a response-supplied internal marker. Recreate it only from + // this response's actual 4xx/5xx status, or remove it from other responses. + headers.delete(INTERNAL_DEIXIC_PUBLIC_HTTP_STATUS_HEADER); + if (preserveStatus) { + headers.set(INTERNAL_DEIXIC_PUBLIC_HTTP_STATUS_HEADER, String(response.status)); + } + return new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers, + }); +} + +class CredentialIdentity { + private subject: string | undefined; + private scopes: Set | undefined; + private organizationId: string | undefined; + private workspaceId: string | undefined; + private sawCredential = false; + + constructor(private readonly scope: Readonly) {} + + check(credential: PublicCredential | null): PublicCredential | null { + if (!credential) { + if (this.sawCredential) { + throw credentialError("credential source removed an explicit credential"); + } + return null; + } + this.sawCredential = true; + + const claims = this.claims(credential); + if (claims.organizationId) this.organizationId = claims.organizationId; + if (claims.workspaceId) this.workspaceId = claims.workspaceId; + if (claims.subject) this.subject = claims.subject; + if (claims.scopes.size > 0 && !this.scopes) this.scopes = claims.scopes; + return credential; + } + + validate(credential: PublicCredential): void { + this.claims(credential); + } + + private claims(credential: PublicCredential): { + organizationId?: string; + workspaceId?: string; + subject?: string; + scopes: Set; + } { + const organizationId = credential.organizationId?.trim(); + const workspaceId = credential.workspaceId?.trim(); + if (organizationId && organizationId !== this.scope.organizationId) { + throw credentialError("credential organizationId does not match the client scope"); + } + if (workspaceId && workspaceId !== this.scope.workspaceId) { + throw credentialError("credential workspaceId does not match the client scope"); + } + if (this.organizationId && !organizationId) { + throw credentialError("credential refresh removed its declared organizationId"); + } + if (this.workspaceId && !workspaceId) { + throw credentialError("credential refresh removed its declared workspaceId"); + } + const subject = credential.subject?.trim(); + if (this.subject && !subject) { + throw credentialError("credential refresh removed the authenticated subject"); + } + if (subject && this.subject && subject !== this.subject) { + throw credentialError("credential refresh changed the authenticated subject"); + } + const scopes = normalizedScopes(credential.scopes); + if (this.scopes && scopes.size === 0) { + throw credentialError("credential refresh removed its declared OAuth scopes"); + } + if (scopes.size > 0 && this.scopes) { + if (!sameScopes(this.scopes, scopes)) { + throw credentialError("credential refresh changed its declared OAuth scopes"); + } + } + return { organizationId, workspaceId, subject, scopes }; + } +} + +function normalizeScope(scope: PublicScope): Readonly { + return Object.freeze({ + organizationId: required(scope.organizationId, "scope.organizationId"), + workspaceId: required(scope.workspaceId, "scope.workspaceId"), + }); +} + +function required(value: string, field: string): string { + const normalized = value?.trim(); + if (!normalized) throw validationError(`${field} is required`); + return normalized; +} + +/** + * Snapshot the complete protobuf request shape before a unary or pre-page stream + * retry closure captures it. `create()` intentionally preserves some caller + * list/object references; `clone()` prevents refresh-time mutation from + * changing the bytes associated with a caller-owned idempotency key. + */ +function snapshotRequest( + schema: Desc, + init: MessageInitShape, +): MessageShape { + return clone(schema, create(schema, init)); +} + +function cursor(value: bigint, field: string): bigint { + if (typeof value !== "bigint" || value < 0n || value > MAX_OPERATING_CURSOR) { + throw validationError(`${field} must be a non-negative bigint within the operating cursor range`); + } + return value; +} + +function readLimit(value: number | undefined): number { + if (value === undefined) return DEFAULT_THREAD_LIMIT; + if (!Number.isInteger(value) || value < 1 || value > MAX_EVENT_LIMIT) { + throw validationError(`limit must be an integer between 1 and ${MAX_EVENT_LIMIT}`); + } + return value; +} + +function readOffset(value: number | undefined): number | undefined { + if (value === undefined) return undefined; + if (!Number.isInteger(value) || value < 0 || value > MAX_INT32) { + throw validationError(`offset must be a non-negative int32`); + } + return value; +} + +function eventLimit(value: number | undefined): number { + if (value === undefined) return DEFAULT_EVENT_LIMIT; + if (!Number.isInteger(value) || value < 1 || value > MAX_EVENT_LIMIT) { + throw validationError(`limit must be an integer between 1 and ${MAX_EVENT_LIMIT}`); + } + return value; +} + +function normalizedScopes(value: PublicCredential["scopes"]): Set { + const values = typeof value === "string" ? value.split(/\s+/) : value ?? []; + return new Set(values.map((scope) => scope.trim()).filter(Boolean)); +} + +function snapshotCredential( + credential: PublicCredential | null | undefined, +): PublicCredential | null { + if (!credential) return null; + return Object.freeze({ + accessToken: credential.accessToken, + tokenType: credential.tokenType, + subject: credential.subject, + organizationId: credential.organizationId, + workspaceId: credential.workspaceId, + scopes: typeof credential.scopes === "string" + ? credential.scopes + : credential.scopes ? Object.freeze([...credential.scopes]) : undefined, + }); +} + +function copyCredential(credential: PublicCredential): PublicCredential; +function copyCredential(credential: null): null; +function copyCredential(credential: PublicCredential | null): PublicCredential | null; +function copyCredential( + credential: PublicCredential | null, +): PublicCredential | null { + if (!credential) return null; + return { + ...credential, + scopes: typeof credential.scopes === "string" + ? credential.scopes + : credential.scopes ? [...credential.scopes] : undefined, + }; +} + +function sameScopes(left: Set, right: Set): boolean { + return left.size === right.size && [...left].every((scope) => right.has(scope)); +} + +function validationError(message: string): PublicError { + return new PublicError({ message, kind: "validation", status: 400 }); +} + +function credentialError(message: string): PublicError { + return new PublicError({ message, kind: "authentication", status: 401 }); +} + +function trimTrailingSlash(value: string): string { + return value.endsWith("/") ? value.slice(0, -1) : value; +} + +type MaybePromise = T | Promise; diff --git a/sdk/deixic/typescript/src/errors.ts b/sdk/deixic/typescript/src/errors.ts new file mode 100644 index 0000000..d5eb981 --- /dev/null +++ b/sdk/deixic/typescript/src/errors.ts @@ -0,0 +1,150 @@ +import { Code, ConnectError } from "@connectrpc/connect"; + +/** Private transport metadata; intentionally not re-exported from the SDK. */ +export const INTERNAL_DEIXIC_PUBLIC_HTTP_STATUS_HEADER = "x-deixic-product-http-status"; + +/** Stable error categories for product code. */ +export type PublicErrorKind = + | "authentication" + | "authorization" + | "validation" + | "conflict" + | "not_found" + | "unavailable" + | "rate_limited" + | "transport" + | "protocol"; + +/** + * An error returned by the Deixic SDK facade. The original Connect + * error remains its cause so applications can inspect protocol details if they + * need them without coupling ordinary handling to Connect. + */ +export class PublicError extends Error { + readonly kind: PublicErrorKind; + readonly status?: number; + readonly code?: string; + readonly requestId?: string; + readonly traceparent?: string; + + constructor(input: { + message: string; + kind: PublicErrorKind; + status?: number; + code?: string; + requestId?: string; + traceparent?: string; + cause?: unknown; + }) { + super(input.message, { cause: input.cause }); + this.name = "PublicError"; + this.kind = input.kind; + this.status = input.status; + this.code = input.code; + this.requestId = input.requestId; + this.traceparent = input.traceparent; + } +} + +export function asPublicError(error: unknown): PublicError { + if (error instanceof PublicError) return error; + if (error instanceof ConnectError) return fromConnectError(error); + + return new PublicError({ + message: error instanceof Error ? error.message : String(error), + kind: "transport", + cause: error, + }); +} + +export function isUnauthenticated(error: unknown): boolean { + return error instanceof ConnectError && error.code === Code.Unauthenticated; +} + +function fromConnectError(error: ConnectError): PublicError { + const metadata = error.metadata; + const status = preservedHttpStatus(metadata) ?? httpStatusFor(error.code); + return new PublicError({ + message: error.rawMessage || error.message, + kind: errorKindFor(error.code), + status, + code: metadata.get("x-evalops-error-code") + ?? metadata.get("x-error-code") + ?? connectCodeName(error.code), + requestId: metadata.get("x-request-id") ?? undefined, + traceparent: metadata.get("traceparent") ?? undefined, + cause: error, + }); +} + +function preservedHttpStatus(metadata: Headers): number | undefined { + const value = metadata.get(INTERNAL_DEIXIC_PUBLIC_HTTP_STATUS_HEADER); + if (!value || !/^[45]\d{2}$/.test(value)) return undefined; + return Number(value); +} + +function errorKindFor(code: Code): PublicErrorKind { + switch (code) { + case Code.Unauthenticated: + return "authentication"; + case Code.PermissionDenied: + return "authorization"; + case Code.InvalidArgument: + case Code.OutOfRange: + return "validation"; + case Code.AlreadyExists: + case Code.Aborted: + case Code.FailedPrecondition: + return "conflict"; + case Code.NotFound: + return "not_found"; + case Code.ResourceExhausted: + return "rate_limited"; + case Code.Unavailable: + case Code.DeadlineExceeded: + return "unavailable"; + case Code.Canceled: + return "transport"; + default: + return "protocol"; + } +} + +function httpStatusFor(code: Code): number { + switch (code) { + case Code.Canceled: + return 499; + case Code.InvalidArgument: + return 400; + case Code.DeadlineExceeded: + return 504; + case Code.NotFound: + return 404; + case Code.AlreadyExists: + return 409; + case Code.PermissionDenied: + return 403; + case Code.ResourceExhausted: + return 429; + case Code.FailedPrecondition: + return 400; + case Code.Aborted: + return 409; + case Code.OutOfRange: + return 400; + case Code.Unimplemented: + return 501; + case Code.Internal: + case Code.DataLoss: + case Code.Unknown: + return 500; + case Code.Unavailable: + return 503; + case Code.Unauthenticated: + return 401; + } +} + +function connectCodeName(code: Code): string { + return Code[code]?.replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase() ?? "unknown"; +} diff --git a/sdk/deixic/typescript/src/index.ts b/sdk/deixic/typescript/src/index.ts index 200131f..f82725f 100644 --- a/sdk/deixic/typescript/src/index.ts +++ b/sdk/deixic/typescript/src/index.ts @@ -1,11 +1,11 @@ import { Code, ConnectError, type Transport } from "@connectrpc/connect"; import { - createMaestroProductClient, - type MaestroProductAuth, - type MaestroProductClient, -} from "../../../maestro/typescript/src/client.js"; -import { MaestroProductError } from "../../../maestro/typescript/src/errors.js"; + createPublicClient, + type PublicAuth, + type PublicClient, +} from "./client.js"; +import { PublicError } from "./errors.js"; import { TasksClient } from "./tasks.js"; /** Hosted Deixic API origin used when a client does not provide one. */ @@ -27,14 +27,15 @@ export interface DeixicClientOptions { workspaceId: string; baseUrl?: string; apiKey?: string; - auth?: MaestroProductAuth; + auth?: PublicAuth; fetch?: typeof globalThis.fetch; /** Test and server-adapter escape hatch. Product calls remain tenant-bound. */ transport?: Transport; } /** The typed Deixic client returned by {@link createDeixicClient}. */ -export interface DeixicClient extends MaestroProductClient { +export interface DeixicClient extends Pick { readonly tasks: TasksClient; } @@ -55,12 +56,12 @@ export function createDeixicClient(options: DeixicClientOptions): DeixicClient { throw validationError('provide either "apiKey" or "auth", not both'); } - const auth: MaestroProductAuth | undefined = apiKey + const auth: PublicAuth | undefined = apiKey ? { getCredential: () => ({ accessToken: apiKey, tokenType: "Bearer" }) } : options.auth; const baseUrl = checkedBaseUrl(options.baseUrl ?? DEFAULT_DEIXIC_BASE_URL); - const client = createMaestroProductClient({ + const client = createPublicClient({ baseUrl, scope: { organizationId: options.organizationId, @@ -80,7 +81,16 @@ export function createDeixicClient(options: DeixicClientOptions): DeixicClient { }, transport: options.transport, }); - return Object.assign(client, { tasks: new TasksClient(client, baseUrl) }); + // Enumerate supported SDK facades explicitly. + return { + scope: client.scope, + threads: client.threads, + events: client.events, + messages: client.messages, + controls: client.controls, + receipts: client.receipts, + tasks: new TasksClient(client, baseUrl), + }; } export { Task, TasksClient, parseTaskResult } from "./tasks.js"; @@ -101,85 +111,56 @@ function checkedBaseUrl(value: string): string { return cleaned; } -function validationError(message: string): MaestroProductError { - return new MaestroProductError({ message, kind: "validation", status: 400 }); +function validationError(message: string): PublicError { + return new PublicError({ message, kind: "validation", status: 400 }); } export { - observeMaestroAcceptedTurn as observeAcceptedTurn, -} from "../../../maestro/typescript/src/accepted-turn.js"; + observePublicAcceptedTurn as observeAcceptedTurn, +} from "./accepted-turn.js"; export type { - MaestroAcceptedTurnAcceptance as AcceptedTurnAcceptance, - MaestroAcceptedTurnResult as AcceptedTurnResult, - MaestroAcceptedTurnUnfinishedReason as AcceptedTurnUnfinishedReason, - MaestroAcceptedTurnWatchOptions as AcceptedTurnWatchOptions, - MaestroObserveAcceptedTurnInput as ObserveAcceptedTurnInput, -} from "../../../maestro/typescript/src/accepted-turn.js"; + PublicAcceptedTurnAcceptance as AcceptedTurnAcceptance, + PublicAcceptedTurnResult as AcceptedTurnResult, + PublicAcceptedTurnUnfinishedReason as AcceptedTurnUnfinishedReason, + PublicAcceptedTurnWatchOptions as AcceptedTurnWatchOptions, + PublicObserveAcceptedTurnInput as ObserveAcceptedTurnInput, +} from "./accepted-turn.js"; export { - MAESTRO_PRODUCT_APP_CONTEXT_HEADER as DEIXIC_APP_CONTEXT_HEADER, - MAESTRO_PRODUCT_APP_CONTEXT_MAX_HEADER_CHARS as DEIXIC_APP_CONTEXT_MAX_HEADER_CHARS, - encodeMaestroProductAppContextHeader as encodeDeixicAppContextHeader, - encodedMaestroProductAppContextHeaderLength as encodedDeixicAppContextHeaderLength, -} from "../../../maestro/typescript/src/app-context.js"; + DEIXIC_PUBLIC_APP_CONTEXT_HEADER as DEIXIC_APP_CONTEXT_HEADER, + DEIXIC_PUBLIC_APP_CONTEXT_MAX_HEADER_CHARS as DEIXIC_APP_CONTEXT_MAX_HEADER_CHARS, + encodePublicAppContextHeader as encodeDeixicAppContextHeader, + encodedPublicAppContextHeaderLength as encodedDeixicAppContextHeaderLength, +} from "./app-context.js"; export { - MaestroProductError as DeixicError, -} from "../../../maestro/typescript/src/errors.js"; + PublicError as DeixicError, +} from "./errors.js"; export type { - MaestroProductErrorKind as DeixicErrorKind, -} from "../../../maestro/typescript/src/errors.js"; + PublicErrorKind as DeixicErrorKind, +} from "./errors.js"; export type { - MaestroGetReceiptInput as GetReceiptInput, - MaestroAssessComplianceInput as AssessComplianceInput, - MaestroRecordComplianceInput as RecordComplianceInput, - MaestroGetComplianceInput as GetComplianceInput, - MaestroGetThreadInput as GetThreadInput, - MaestroInterruptThreadInput as InterruptThreadInput, - MaestroListThreadEventsInput as ListThreadEventsInput, - MaestroProductAuth as DeixicAuth, - MaestroProductCredential as DeixicCredential, - MaestroResolveReceiptInput as ResolveReceiptInput, - MaestroRespondToThreadInput as RespondToThreadInput, - MaestroSendMessageInput as SendMessageInput, - MaestroWatchThreadInput as WatchThreadInput, -} from "../../../maestro/typescript/src/client.js"; + PublicGetReceiptInput as GetReceiptInput, + PublicGetThreadInput as GetThreadInput, + PublicInterruptThreadInput as InterruptThreadInput, + PublicListThreadEventsInput as ListThreadEventsInput, + PublicAuth as DeixicAuth, + PublicCredential as DeixicCredential, + PublicResolveReceiptInput as ResolveReceiptInput, + PublicRespondToThreadInput as RespondToThreadInput, + PublicSendMessageInput as SendMessageInput, + PublicWatchThreadInput as WatchThreadInput, +} from "./client.js"; export { - ComplianceFindingStatus, OperatingThreadRequestType, OperatingThreadResponseAction, OperatingThreadWaitingReason, OperatingTurnState, ReceiptLifecycleState, -} from "../../../../gen/ts/console/v1/console_pb.js"; +} from "./protocol.js"; -export type { - AssessComplianceSubjectResponse, - ComplianceAssessmentRecord, - ComplianceSubjectAssessment, - ComplianceRequirementFinding, - GetComplianceAssessmentResponse, - RecordComplianceAssessmentResponse, - GetOperatingReceiptResponse, - GetOperatingThreadResponse, - InterruptOperatingThreadResponse, - ListOperatingThreadEventsResponse, - OperatingAttachmentRef, - OperatingCapabilityState, - OperatingChannel, - OperatingModelSelection, - OperatingReceipt, - OperatingReceiptAction, - OperatingThreadEvent, - OperatingThreadExecution, - OperatingThreadResponse, - OperatingThreadTurn, - ResolveOperatingReceiptActionResponse, - RespondOperatingThreadResponse, - SubmitOperatingMessageResponse, - WatchOperatingThreadResponse, -} from "../../../../gen/ts/console/v1/console_pb.js"; +export * from "./protocol.js"; diff --git a/sdk/deixic/typescript/src/protocol.ts b/sdk/deixic/typescript/src/protocol.ts new file mode 100644 index 0000000..90b0256 --- /dev/null +++ b/sdk/deixic/typescript/src/protocol.ts @@ -0,0 +1,2973 @@ +// @generated by protoc-gen-es v2.12.1 with parameter "target=ts,import_extension=.js" +// @generated from file deixicpublic/v1/sdk.proto (package deixicpublic.v1, syntax proto3) +/* eslint-disable */ + +import type { GenEnum, GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv2"; +import { enumDesc, fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2"; +import type { Timestamp } from "@bufbuild/protobuf/wkt"; +import { file_google_protobuf_timestamp } from "@bufbuild/protobuf/wkt"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file deixicpublic/v1/sdk.proto. + */ +export const file_deixicpublic_v1_sdk: GenFile = /*@__PURE__*/ + fileDesc("ChlkZWl4aWNwdWJsaWMvdjEvc2RrLnByb3RvEg9kZWl4aWNwdWJsaWMudjEiNgoFU2NvcGUSFwoPb3JnYW5pemF0aW9uX2lkGAEgASgJEhQKDHdvcmtzcGFjZV9pZBgCIAEoCSJTCgtFcnJvckRldGFpbBIMCgRjb2RlGAEgASgJEg8KB21lc3NhZ2UYAiABKAkSEgoKcmVxdWVzdF9pZBgDIAEoCRIRCglyZXRyeWFibGUYBCABKAgiugMKCFRhc2tUdXJuEg8KB3R1cm5faWQYASABKAkSEAoIc2VxdWVuY2UYAiABKAMSFwoPdXNlcl9tZXNzYWdlX2lkGAMgASgJEhwKFGFzc2lzdGFudF9tZXNzYWdlX2lkGAQgASgJEikKBXN0YXRlGAUgASgOMhouZGVpeGljcHVibGljLnYxLlR1cm5TdGF0ZRI2Cg53YWl0aW5nX3JlYXNvbhgGIAEoDjIeLmRlaXhpY3B1YmxpYy52MS5XYWl0aW5nUmVhc29uEhQKDGZpcnN0X2N1cnNvchgHIAEoAxITCgtsYXN0X2N1cnNvchgIIAEoAxI0Cg50ZXJtaW5hbF9lcnJvchgJIAEoCzIcLmRlaXhpY3B1YmxpYy52MS5FcnJvckRldGFpbBIuCgpjcmVhdGVkX2F0GAogASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIuCgp1cGRhdGVkX2F0GAsgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIwCgxjb21wbGV0ZWRfYXQYDCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wIsQBCgZUaHJlYWQSCgoCaWQYASABKAkSDQoFdGl0bGUYAiABKAkSFQoNcmVwbGF5X2N1cnNvchgDIAEoAxIcChRhY3RpdmVfdHVybl9zZXF1ZW5jZRgEIAEoAxIuCgp1cGRhdGVkX2F0GAUgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBIUCgx1bnJlYWRfY291bnQYBiABKAUSEgoKb3Blbl9jb3VudBgHIAEoBRIQCghhcmNoaXZlZBgIIAEoCCKYAQoLVGFza01lc3NhZ2USCgoCaWQYASABKAkSKgoEcm9sZRgCIAEoDjIcLmRlaXhpY3B1YmxpYy52MS5NZXNzYWdlUm9sZRIMCgRib2R5GAMgASgJEi4KCmNyZWF0ZWRfYXQYBCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEhMKC3JlY2VpcHRfaWRzGAUgAygJIkkKEUV2aWRlbmNlUmVmZXJlbmNlEgwKBGtpbmQYASABKAkSCgoCaWQYAiABKAkSDQoFbGFiZWwYAyABKAkSCwoDdXJpGAQgASgJIvgCCglUYXNrRXZlbnQSDgoGY3Vyc29yGAEgASgDEgoKAmlkGAIgASgJEg8KB3R1cm5faWQYAyABKAkSKAoEa2luZBgEIAEoDjIaLmRlaXhpY3B1YmxpYy52MS5FdmVudEtpbmQSDAoEdGV4dBgFIAEoCRI0CghldmlkZW5jZRgGIAMoCzIiLmRlaXhpY3B1YmxpYy52MS5FdmlkZW5jZVJlZmVyZW5jZRIuCgpjcmVhdGVkX2F0GAcgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBISCgpyZXF1ZXN0X2lkGAggASgJEjIKDHJlcXVlc3Rfa2luZBgJIAEoDjIcLmRlaXhpY3B1YmxpYy52MS5SZXF1ZXN0S2luZBIRCgl0b29sX25hbWUYCiABKAkSDwoHY2FsbF9pZBgLIAEoCRI0Cg50ZXJtaW5hbF9lcnJvchgMIAEoCzIcLmRlaXhpY3B1YmxpYy52MS5FcnJvckRldGFpbCJwCg1SZWNlaXB0QWN0aW9uEgoKAmlkGAEgASgJEg0KBWxhYmVsGAIgASgJEgwKBGtpbmQYAyABKAkSHQoVcmVxdWlyZXNfY29uZmlybWF0aW9uGAQgASgIEhcKD2Rpc2FibGVkX3JlYXNvbhgFIAEoCSJ4CgxDb2RpbmdPdXRwdXQSDAoEcGF0aBgBIAEoCRIRCglvYmplY3RfaWQYAiABKAkSEgoKdmVyc2lvbl9pZBgDIAEoCRIOCgZzaGEyNTYYBCABKAkSEgoKc2l6ZV9ieXRlcxgFIAEoBBIPCgdjb250ZW50GAYgASgMIqsBChBDb2RpbmdBY2NlcHRhbmNlEhAKCGFjY2VwdGVkGAEgASgIEhcKD2NvbnRyYWN0X2RpZ2VzdBgCIAEoCRIZChFzdWJtaXNzaW9uX2RpZ2VzdBgDIAEoCRIPCgdyZWFzb25zGAQgAygJEhAKCHJldmlzaW9uGAUgASgJEi4KB291dHB1dHMYBiADKAsyHS5kZWl4aWNwdWJsaWMudjEuQ29kaW5nT3V0cHV0Is4CCgdSZWNlaXB0EgoKAmlkGAEgASgJEgwKBGtpbmQYAiABKAkSDQoFdGl0bGUYAyABKAkSDwoHc3VtbWFyeRgEIAEoCRIsCgVzdGF0ZRgFIAEoDjIdLmRlaXhpY3B1YmxpYy52MS5SZWNlaXB0U3RhdGUSLgoKdXBkYXRlZF9hdBgGIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXASNwoPYWxsb3dlZF9hY3Rpb25zGAcgAygLMh4uZGVpeGljcHVibGljLnYxLlJlY2VpcHRBY3Rpb24SNAoIZXZpZGVuY2UYCCADKAsyIi5kZWl4aWNwdWJsaWMudjEuRXZpZGVuY2VSZWZlcmVuY2USPAoRY29kaW5nX2FjY2VwdGFuY2UYCSABKAsyIS5kZWl4aWNwdWJsaWMudjEuQ29kaW5nQWNjZXB0YW5jZSIxCg5Nb2RlbFNlbGVjdGlvbhIQCghwcm92aWRlchgBIAEoCRINCgVtb2RlbBgCIAEoCSJWCg5BdmFpbGFibGVNb2RlbBIQCghwcm92aWRlchgBIAEoCRINCgVtb2RlbBgCIAEoCRINCgVyZWFkeRgDIAEoCBIUCgxkaXNwbGF5X25hbWUYBCABKAki/gEKDlNldHVwUmVhZGluZXNzEhIKCmFjY2Vzc2libGUYASABKAgSHAoUbWlzc2luZ19yZXF1aXJlbWVudHMYAiADKAkSMgoJc2VsZWN0aW9uGAMgASgLMh8uZGVpeGljcHVibGljLnYxLk1vZGVsU2VsZWN0aW9uEjYKDWRlZmF1bHRfbW9kZWwYBCABKAsyHy5kZWl4aWNwdWJsaWMudjEuQXZhaWxhYmxlTW9kZWwSOQoQYXZhaWxhYmxlX21vZGVscxgFIAMoCzIfLmRlaXhpY3B1YmxpYy52MS5BdmFpbGFibGVNb2RlbBITCgtuZXh0X2FjdGlvbhgGIAEoCSKKAQoYR2V0TW9kZWxSZWFkaW5lc3NSZXF1ZXN0EiUKBXNjb3BlGAEgASgLMhYuZGVpeGljcHVibGljLnYxLlNjb3BlEjIKCXNlbGVjdGlvbhgCIAEoCzIfLmRlaXhpY3B1YmxpYy52MS5Nb2RlbFNlbGVjdGlvbhITCgtlbnZpcm9ubWVudBgDIAEoCSKqAgoZR2V0TW9kZWxSZWFkaW5lc3NSZXNwb25zZRIlCgVzY29wZRgBIAEoCzIWLmRlaXhpY3B1YmxpYy52MS5TY29wZRIyCglzZWxlY3Rpb24YAiABKAsyHy5kZWl4aWNwdWJsaWMudjEuTW9kZWxTZWxlY3Rpb24SEwoLZW52aXJvbm1lbnQYAyABKAkSMwoFc3RhdGUYBCABKA4yJC5kZWl4aWNwdWJsaWMudjEuTW9kZWxSZWFkaW5lc3NTdGF0ZRI2CgxuZXh0X2FjdGlvbnMYBSADKA4yIC5kZWl4aWNwdWJsaWMudjEuTW9kZWxOZXh0QWN0aW9uEjAKDGV2YWx1YXRlZF9hdBgGIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXAibwoKQ2xpZW50UnVsZRIKCgJpZBgBIAEoCRINCgV0aXRsZRgCIAEoCRIVCg1ib2R5X21hcmtkb3duGAMgASgJEi8KBXNjb3BlGAQgASgOMiAuZGVpeGljcHVibGljLnYxLkNsaWVudFJ1bGVTY29wZSJMCgtDbGllbnRTa2lsbBIKCgJpZBgBIAEoCRIOCgZzb3VyY2UYAiABKAkSDwoHdmVyc2lvbhgDIAEoCRIQCghyZXF1aXJlZBgEIAEoCCJHCg9DbGllbnRNY3BTZXJ2ZXISDAoEbmFtZRgBIAEoCRITCgt1cmxfcGF0dGVybhgCIAEoCRIRCgl0cmFuc3BvcnQYAyABKAkicgoPQ2xpZW50TWNwUG9saWN5EiwKBG1vZGUYASABKA4yHi5kZWl4aWNwdWJsaWMudjEuQ2xpZW50TWNwTW9kZRIxCgdzZXJ2ZXJzGAIgAygLMiAuZGVpeGljcHVibGljLnYxLkNsaWVudE1jcFNlcnZlciI+ChVHZXRDbGllbnRTZXR1cFJlcXVlc3QSJQoFc2NvcGUYASABKAsyFi5kZWl4aWNwdWJsaWMudjEuU2NvcGUipQIKFkdldENsaWVudFNldHVwUmVzcG9uc2USJQoFc2NvcGUYASABKAsyFi5kZWl4aWNwdWJsaWMudjEuU2NvcGUSDwoHdmVyc2lvbhgCIAEoBBItCglpc3N1ZWRfYXQYAyABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wEioKBXJ1bGVzGAQgAygLMhsuZGVpeGljcHVibGljLnYxLkNsaWVudFJ1bGUSLAoGc2tpbGxzGAUgAygLMhwuZGVpeGljcHVibGljLnYxLkNsaWVudFNraWxsEi0KA21jcBgGIAEoCzIgLmRlaXhpY3B1YmxpYy52MS5DbGllbnRNY3BQb2xpY3kSGwoTc2FuZGJveF9wb2xpY3lfdG9tbBgHIAEoCSI+Cg1Jc3N1ZUV2aWRlbmNlEgwKBGtpbmQYASABKAkSEQoJc291cmNlX2lkGAIgASgJEgwKBHRleHQYAyABKAkiawoMSXNzdWVDb250ZXh0EhoKEnJlcHJvZHVjdGlvbl9zdGVwcxgBIAEoCRINCgVtb2RlbBgCIAEoCRIwCghldmlkZW5jZRgDIAMoCzIeLmRlaXhpY3B1YmxpYy52MS5Jc3N1ZUV2aWRlbmNlIuwBChhTdWJtaXRJc3N1ZVJlcG9ydFJlcXVlc3QSJQoFc2NvcGUYASABKAsyFi5kZWl4aWNwdWJsaWMudjEuU2NvcGUSEwoLZGVzY3JpcHRpb24YAiABKAkSGQoRZXhwZWN0ZWRfYmVoYXZpb3IYAyABKAkSEwoLYXBwX3ZlcnNpb24YBCABKAkSGwoTaW5jbHVkZV9kaWFnbm9zdGljcxgFIAEoCBIXCg9pZGVtcG90ZW5jeV9rZXkYBiABKAkSLgoHY29udGV4dBgHIAEoCzIdLmRlaXhpY3B1YmxpYy52MS5Jc3N1ZUNvbnRleHQiLAoLSXNzdWVSZXBvcnQSCgoCaWQYASABKAkSEQoJcmVmZXJlbmNlGAIgASgJIkkKGVN1Ym1pdElzc3VlUmVwb3J0UmVzcG9uc2USLAoGcmVwb3J0GAEgASgLMhwuZGVpeGljcHVibGljLnYxLklzc3VlUmVwb3J0IjEKDUJ1c2luZXNzTW9uZXkSDgoGYW1vdW50GAEgASgJEhAKCGN1cnJlbmN5GAIgASgJIiwKF0J1c2luZXNzT2JqZWN0UmVmZXJlbmNlEhEKCW9iamVjdF9pZBgBIAEoCSI4ChlCdXNpbmVzc0FydGlmYWN0UmVmZXJlbmNlEhsKE2FydGlmYWN0X3ZlcnNpb25faWQYASABKAkiIgoQQnVzaW5lc3NUZXh0TGlzdBIOCgZ2YWx1ZXMYASADKAkimwMKEkJ1c2luZXNzRmllbGRWYWx1ZRIQCghmaWVsZF9pZBgBIAEoCRIOCgR0ZXh0GAIgASgJSAASEQoHaW50ZWdlchgDIAEoA0gAEhEKB2Jvb2xlYW4YBCABKAhIABIRCgdkZWNpbWFsGAUgASgJSAASLwoFbW9uZXkYBiABKAsyHi5kZWl4aWNwdWJsaWMudjEuQnVzaW5lc3NNb25leUgAEhQKCmVudW1fdmFsdWUYByABKAlIABIOCgRkYXRlGAggASgJSAASEwoJdGltZXN0YW1wGAkgASgJSAASPQoJcmVmZXJlbmNlGAogASgLMiguZGVpeGljcHVibGljLnYxLkJ1c2luZXNzT2JqZWN0UmVmZXJlbmNlSAASPgoIYXJ0aWZhY3QYCyABKAsyKi5kZWl4aWNwdWJsaWMudjEuQnVzaW5lc3NBcnRpZmFjdFJlZmVyZW5jZUgAEjYKCXRleHRfbGlzdBgMIAEoCzIhLmRlaXhpY3B1YmxpYy52MS5CdXNpbmVzc1RleHRMaXN0SABCBwoFdmFsdWUi2QEKDkJ1c2luZXNzT2JqZWN0EhEKCW9iamVjdF9pZBgBIAEoCRIPCgd0eXBlX2lkGAIgASgJEhcKD3NjaGVtYV9yZXZpc2lvbhgDIAEoAxIQCghyZXZpc2lvbhgEIAEoAxIzCgZ2YWx1ZXMYBSADKAsyIy5kZWl4aWNwdWJsaWMudjEuQnVzaW5lc3NGaWVsZFZhbHVlEg8KB2RlbGV0ZWQYBiABKAgSEgoKdXBkYXRlZF9hdBgJIAEoCRISCgpjcmVhdGVkX2F0GAogASgJSgQIBxAISgQICBAJIsQBChtDcmVhdGVCdXNpbmVzc09iamVjdFJlcXVlc3QSFwoPb3JnYW5pemF0aW9uX2lkGAEgASgJEhQKDHdvcmtzcGFjZV9pZBgCIAEoCRIXCg9pZGVtcG90ZW5jeV9rZXkYAyABKAkSDwoHdHlwZV9pZBgEIAEoCRIXCg9zY2hlbWFfcmV2aXNpb24YBSABKAMSMwoGdmFsdWVzGAYgAygLMiMuZGVpeGljcHVibGljLnYxLkJ1c2luZXNzRmllbGRWYWx1ZSJPChxDcmVhdGVCdXNpbmVzc09iamVjdFJlc3BvbnNlEi8KBm9iamVjdBgBIAEoCzIfLmRlaXhpY3B1YmxpYy52MS5CdXNpbmVzc09iamVjdCJoChhHZXRCdXNpbmVzc09iamVjdFJlcXVlc3QSFwoPb3JnYW5pemF0aW9uX2lkGAEgASgJEhQKDHdvcmtzcGFjZV9pZBgCIAEoCRIRCglvYmplY3RfaWQYBCABKAlKBAgDEARKBAgFEAYiTAoZR2V0QnVzaW5lc3NPYmplY3RSZXNwb25zZRIvCgZvYmplY3QYASABKAsyHy5kZWl4aWNwdWJsaWMudjEuQnVzaW5lc3NPYmplY3Qi4QEKG1VwZGF0ZUJ1c2luZXNzT2JqZWN0UmVxdWVzdBIXCg9vcmdhbml6YXRpb25faWQYASABKAkSFAoMd29ya3NwYWNlX2lkGAIgASgJEhcKD2lkZW1wb3RlbmN5X2tleRgDIAEoCRIRCglvYmplY3RfaWQYBCABKAkSGQoRZXhwZWN0ZWRfcmV2aXNpb24YBSABKAMSMwoGdmFsdWVzGAYgAygLMiMuZGVpeGljcHVibGljLnYxLkJ1c2luZXNzRmllbGRWYWx1ZRIXCg9zY2hlbWFfcmV2aXNpb24YByABKAMiTwocVXBkYXRlQnVzaW5lc3NPYmplY3RSZXNwb25zZRIvCgZvYmplY3QYASABKAsyHy5kZWl4aWNwdWJsaWMudjEuQnVzaW5lc3NPYmplY3QikwEKG0RlbGV0ZUJ1c2luZXNzT2JqZWN0UmVxdWVzdBIXCg9vcmdhbml6YXRpb25faWQYASABKAkSFAoMd29ya3NwYWNlX2lkGAIgASgJEhcKD2lkZW1wb3RlbmN5X2tleRgDIAEoCRIRCglvYmplY3RfaWQYBCABKAkSGQoRZXhwZWN0ZWRfcmV2aXNpb24YBSABKAMiTwocRGVsZXRlQnVzaW5lc3NPYmplY3RSZXNwb25zZRIvCgZvYmplY3QYASABKAsyHy5kZWl4aWNwdWJsaWMudjEuQnVzaW5lc3NPYmplY3QibwoQR2V0VGhyZWFkUmVxdWVzdBIlCgVzY29wZRgBIAEoCzIWLmRlaXhpY3B1YmxpYy52MS5TY29wZRIRCgl0aHJlYWRfaWQYAiABKAkSDQoFbGltaXQYAyABKAUSEgoKcGFnZV90b2tlbhgEIAEoCSKiAgoRR2V0VGhyZWFkUmVzcG9uc2USJwoGdGhyZWFkGAEgASgLMhcuZGVpeGljcHVibGljLnYxLlRocmVhZBIuCghtZXNzYWdlcxgCIAMoCzIcLmRlaXhpY3B1YmxpYy52MS5UYXNrTWVzc2FnZRIqCghyZWNlaXB0cxgDIAMoCzIYLmRlaXhpY3B1YmxpYy52MS5SZWNlaXB0EigKBXR1cm5zGAQgAygLMhkuZGVpeGljcHVibGljLnYxLlRhc2tUdXJuEhUKDXJlcGxheV9jdXJzb3IYBSABKAMSFwoPbmV4dF9wYWdlX3Rva2VuGAYgASgJEi4KBXNldHVwGAcgASgLMh8uZGVpeGljcHVibGljLnYxLlNldHVwUmVhZGluZXNzIk0KEkxpc3RUaHJlYWRzUmVxdWVzdBIlCgVzY29wZRgBIAEoCzIWLmRlaXhpY3B1YmxpYy52MS5TY29wZRIQCghhcmNoaXZlZBgCIAEoCCI/ChNMaXN0VGhyZWFkc1Jlc3BvbnNlEigKB3RocmVhZHMYASADKAsyFy5kZWl4aWNwdWJsaWMudjEuVGhyZWFkIl4KE1JlbmFtZVRocmVhZFJlcXVlc3QSJQoFc2NvcGUYASABKAsyFi5kZWl4aWNwdWJsaWMudjEuU2NvcGUSEQoJdGhyZWFkX2lkGAIgASgJEg0KBXRpdGxlGAMgASgJIlAKFFJlbmFtZVRocmVhZFJlc3BvbnNlEicKBnRocmVhZBgBIAEoCzIXLmRlaXhpY3B1YmxpYy52MS5UaHJlYWQSDwoHY2hhbmdlZBgCIAEoCCJ7ChRBcmNoaXZlVGhyZWFkUmVxdWVzdBIlCgVzY29wZRgBIAEoCzIWLmRlaXhpY3B1YmxpYy52MS5TY29wZRIRCgl0aHJlYWRfaWQYAiABKAkSEAoIYXJjaGl2ZWQYAyABKAgSFwoPaWRlbXBvdGVuY3lfa2V5GAQgASgJImMKFUFyY2hpdmVUaHJlYWRSZXNwb25zZRInCgZ0aHJlYWQYASABKAsyFy5kZWl4aWNwdWJsaWMudjEuVGhyZWFkEg8KB2NoYW5nZWQYAiABKAgSEAoIcmVwbGF5ZWQYAyABKAgicgoRTGlzdEV2ZW50c1JlcXVlc3QSJQoFc2NvcGUYASABKAsyFi5kZWl4aWNwdWJsaWMudjEuU2NvcGUSEQoJdGhyZWFkX2lkGAIgASgJEhQKDGFmdGVyX2N1cnNvchgDIAEoAxINCgVsaW1pdBgEIAEoBSLdAQoSTGlzdEV2ZW50c1Jlc3BvbnNlEioKBmV2ZW50cxgBIAMoCzIaLmRlaXhpY3B1YmxpYy52MS5UYXNrRXZlbnQSEwoLbmV4dF9jdXJzb3IYAiABKAMSEAoIaGFzX21vcmUYAyABKAgSFgoOcmVzZXRfcmVxdWlyZWQYBCABKAgSKQoIc25hcHNob3QYBSABKAsyFy5kZWl4aWNwdWJsaWMudjEuVGhyZWFkEjEKDnNuYXBzaG90X3R1cm5zGAYgAygLMhkuZGVpeGljcHVibGljLnYxLlRhc2tUdXJuImQKEldhdGNoRXZlbnRzUmVxdWVzdBIlCgVzY29wZRgBIAEoCzIWLmRlaXhpY3B1YmxpYy52MS5TY29wZRIRCgl0aHJlYWRfaWQYAiABKAkSFAoMYWZ0ZXJfY3Vyc29yGAMgASgDIswBChNXYXRjaEV2ZW50c1Jlc3BvbnNlEioKBmV2ZW50cxgBIAMoCzIaLmRlaXhpY3B1YmxpYy52MS5UYXNrRXZlbnQSEwoLbmV4dF9jdXJzb3IYAiABKAMSFgoOcmVzZXRfcmVxdWlyZWQYAyABKAgSKQoIc25hcHNob3QYBCABKAsyFy5kZWl4aWNwdWJsaWMudjEuVGhyZWFkEjEKDnNuYXBzaG90X3R1cm5zGAUgAygLMhkuZGVpeGljcHVibGljLnYxLlRhc2tUdXJuIv4BCg5Db2RpbmdDb250cmFjdBIVCg1yZXBvc2l0b3J5X2lkGAEgASgJEhIKCmdlbmVyYXRpb24YAiABKAQSHgoWcmVxdWlyZWRfYXNzZXJ0aW9uX2lkcxgDIAMoCRIWCg5yZXF1aXJlX3JldmlldxgEIAEoCBIYChByZXF1aXJlX2JlaGF2aW9yGAUgASgIEh4KFnJlYWRpbmVzc19yZXF1aXJlbWVudHMYBiADKAkSGAoQYXV0aG9yaXplZF9za2lwcxgHIAMoCRIfChdhdXRob3JpemVkX2Rpc3Bvc2l0aW9ucxgIIAMoCRIUCgxvdXRwdXRfcGF0aHMYCSADKAkivwIKEVN1Ym1pdFRhc2tSZXF1ZXN0EiUKBXNjb3BlGAEgASgLMhYuZGVpeGljcHVibGljLnYxLlNjb3BlEhEKCXRocmVhZF9pZBgCIAEoCRIMCgRib2R5GAMgASgJEhcKD2lkZW1wb3RlbmN5X2tleRgEIAEoCRIcChRjb250aW51YXRpb25fdGFza19pZBgFIAEoCRIaChJyZWZlcmVuY2VfdGFza19pZHMYBiADKAkSOAoPbW9kZWxfc2VsZWN0aW9uGAcgASgLMh8uZGVpeGljcHVibGljLnYxLk1vZGVsU2VsZWN0aW9uEjgKD2NvZGluZ19jb250cmFjdBgIIAEoCzIfLmRlaXhpY3B1YmxpYy52MS5Db2RpbmdDb250cmFjdBIbChNwcm9qZWN0X3Jlc291cmNlX2lkGAkgASgJIrgBChJTdWJtaXRUYXNrUmVzcG9uc2USLQoHbWVzc2FnZRgBIAEoCzIcLmRlaXhpY3B1YmxpYy52MS5UYXNrTWVzc2FnZRIwCg1hY2NlcHRlZF90dXJuGAIgASgLMhkuZGVpeGljcHVibGljLnYxLlRhc2tUdXJuEhUKDXJlcGxheV9jdXJzb3IYAyABKAMSKgoIcmVjZWlwdHMYBCADKAsyGC5kZWl4aWNwdWJsaWMudjEuUmVjZWlwdCKKAQoUSW50ZXJydXB0VGFza1JlcXVlc3QSJQoFc2NvcGUYASABKAsyFi5kZWl4aWNwdWJsaWMudjEuU2NvcGUSEQoJdGhyZWFkX2lkGAIgASgJEg8KB3R1cm5faWQYAyABKAkSFwoPaWRlbXBvdGVuY3lfa2V5GAQgASgJEg4KBnJlYXNvbhgFIAEoCSJ7ChVJbnRlcnJ1cHRUYXNrUmVzcG9uc2USDwoHdHVybl9pZBgBIAEoCRIQCghyZXBsYXllZBgCIAEoCBIoCgV0dXJucxgDIAMoCzIZLmRlaXhpY3B1YmxpYy52MS5UYXNrVHVybhIVCg1yZXBsYXlfY3Vyc29yGAQgASgDIqcCChdSZXNwb25kVG9SZXF1ZXN0UmVxdWVzdBIlCgVzY29wZRgBIAEoCzIWLmRlaXhpY3B1YmxpYy52MS5TY29wZRIRCgl0aHJlYWRfaWQYAiABKAkSDwoHdHVybl9pZBgDIAEoCRISCgpyZXF1ZXN0X2lkGAQgASgJEg8KB2NhbGxfaWQYBSABKAkSMgoMcmVxdWVzdF9raW5kGAYgASgOMhwuZGVpeGljcHVibGljLnYxLlJlcXVlc3RLaW5kEi8KBmFjdGlvbhgHIAEoDjIfLmRlaXhpY3B1YmxpYy52MS5SZXNwb25zZUFjdGlvbhIMCgR0ZXh0GAggASgJEhAKCGlzX2Vycm9yGAkgASgIEhcKD2lkZW1wb3RlbmN5X2tleRgKIAEoCSJtChhSZXNwb25kVG9SZXF1ZXN0UmVzcG9uc2USEAoIcmVwbGF5ZWQYASABKAgSKAoFdHVybnMYAiADKAsyGS5kZWl4aWNwdWJsaWMudjEuVGFza1R1cm4SFQoNcmVwbGF5X2N1cnNvchgDIAEoAyKIAQoRR2V0UmVjZWlwdFJlcXVlc3QSJQoFc2NvcGUYASABKAsyFi5kZWl4aWNwdWJsaWMudjEuU2NvcGUSEgoKcmVjZWlwdF9pZBgCIAEoCRIRCgl0aHJlYWRfaWQYAyABKAkSJQodaW5jbHVkZV9jb2Rpbmdfb3V0cHV0X2NvbnRlbnQYBCABKAgiPwoSR2V0UmVjZWlwdFJlc3BvbnNlEikKB3JlY2VpcHQYASABKAsyGC5kZWl4aWNwdWJsaWMudjEuUmVjZWlwdCKEAQobUmVzb2x2ZVJlY2VpcHRBY3Rpb25SZXF1ZXN0EiUKBXNjb3BlGAEgASgLMhYuZGVpeGljcHVibGljLnYxLlNjb3BlEhIKCnJlY2VpcHRfaWQYAiABKAkSEQoJYWN0aW9uX2lkGAMgASgJEhcKD2lkZW1wb3RlbmN5X2tleRgEIAEoCSJJChxSZXNvbHZlUmVjZWlwdEFjdGlvblJlc3BvbnNlEikKB3JlY2VpcHQYASABKAsyGC5kZWl4aWNwdWJsaWMudjEuUmVjZWlwdCrXAQoJVHVyblN0YXRlEhoKFlRVUk5fU1RBVEVfVU5TUEVDSUZJRUQQABIXChNUVVJOX1NUQVRFX0FDQ0VQVEVEEAESFgoSVFVSTl9TVEFURV9SVU5OSU5HEAISFgoSVFVSTl9TVEFURV9XQUlUSU5HEAMSGAoUVFVSTl9TVEFURV9SRVNQT05ERUQQBBIYChRUVVJOX1NUQVRFX0NPTVBMRVRFRBAFEhUKEVRVUk5fU1RBVEVfRkFJTEVEEAYSGgoWVFVSTl9TVEFURV9JTlRFUlJVUFRFRBAHKq4BCg1XYWl0aW5nUmVhc29uEh4KGldBSVRJTkdfUkVBU09OX1VOU1BFQ0lGSUVEEAASGwoXV0FJVElOR19SRUFTT05fQVBQUk9WQUwQARIdChlXQUlUSU5HX1JFQVNPTl9VU0VSX0lOUFVUEAISHgoaV0FJVElOR19SRUFTT05fQ0xJRU5UX1RPT0wQAxIhCh1XQUlUSU5HX1JFQVNPTl9FWFRFUk5BTF9SRVRSWRAEKncKC01lc3NhZ2VSb2xlEhwKGE1FU1NBR0VfUk9MRV9VTlNQRUNJRklFRBAAEhUKEU1FU1NBR0VfUk9MRV9VU0VSEAESGgoWTUVTU0FHRV9ST0xFX0FTU0lTVEFOVBACEhcKE01FU1NBR0VfUk9MRV9TWVNURU0QAyqHAwoJRXZlbnRLaW5kEhoKFkVWRU5UX0tJTkRfVU5TUEVDSUZJRUQQABIcChhFVkVOVF9LSU5EX1RVUk5fQUNDRVBURUQQARIbChdFVkVOVF9LSU5EX1RVUk5fU1RBUlRFRBACEhcKE0VWRU5UX0tJTkRfUFJPR1JFU1MQAxIgChxFVkVOVF9LSU5EX0FQUFJPVkFMX1JFUVVJUkVEEAQSHQoZRVZFTlRfS0lORF9JTlBVVF9SRVFVSVJFRBAFEiAKHEVWRU5UX0tJTkRfQVJUSUZBQ1RfUkVDT1JERUQQBhIdChlFVkVOVF9LSU5EX1RVUk5fQ09NUExFVEVEEAcSGgoWRVZFTlRfS0lORF9UVVJOX0ZBSUxFRBAIEh8KG0VWRU5UX0tJTkRfVFVSTl9JTlRFUlJVUFRFRBAJEiMKH0VWRU5UX0tJTkRfQ0xJRU5UX1RPT0xfUkVRVUlSRUQQChImCiJFVkVOVF9LSU5EX0VYVEVSTkFMX1JFVFJZX1JFUVVJUkVEEAsqogEKC1JlcXVlc3RLaW5kEhwKGFJFUVVFU1RfS0lORF9VTlNQRUNJRklFRBAAEhkKFVJFUVVFU1RfS0lORF9BUFBST1ZBTBABEhsKF1JFUVVFU1RfS0lORF9VU0VSX0lOUFVUEAISHAoYUkVRVUVTVF9LSU5EX0NMSUVOVF9UT09MEAMSHwobUkVRVUVTVF9LSU5EX0VYVEVSTkFMX1JFVFJZEAQqoAMKDFJlY2VpcHRTdGF0ZRIdChlSRUNFSVBUX1NUQVRFX1VOU1BFQ0lGSUVEEAASGQoVUkVDRUlQVF9TVEFURV9VTktOT1dOEAESGgoWUkVDRUlQVF9TVEFURV9QUk9QT1NFRBACEhgKFFJFQ0VJUFRfU1RBVEVfUVVFVUVEEAMSIgoeUkVDRUlQVF9TVEFURV9XQUlUSU5HX0FQUFJPVkFMEAQSGQoVUkVDRUlQVF9TVEFURV9CTE9DS0VEEAUSHQoZUkVDRUlQVF9TVEFURV9ORUVEU19JTlBVVBAGEh0KGVJFQ0VJUFRfU1RBVEVfVU5BVkFJTEFCTEUQBxIZChVSRUNFSVBUX1NUQVRFX1JVTk5JTkcQCBIbChdSRUNFSVBUX1NUQVRFX1NVQ0NFRURFRBAJEhoKFlJFQ0VJUFRfU1RBVEVfVkVSSUZJRUQQChIYChRSRUNFSVBUX1NUQVRFX0RFTklFRBALEhsKF1JFQ0VJUFRfU1RBVEVfQ0FOQ0VMTEVEEAwSGAoUUkVDRUlQVF9TVEFURV9GQUlMRUQQDSrAAgoTTW9kZWxSZWFkaW5lc3NTdGF0ZRIlCiFNT0RFTF9SRUFESU5FU1NfU1RBVEVfVU5TUEVDSUZJRUQQABIfChtNT0RFTF9SRUFESU5FU1NfU1RBVEVfUkVBRFkQARItCilNT0RFTF9SRUFESU5FU1NfU1RBVEVfQUNUSVZBVElPTl9SRVFVSVJFRBACEioKJk1PREVMX1JFQURJTkVTU19TVEFURV9GVU5ESU5HX1JFUVVJUkVEEAMSJwojTU9ERUxfUkVBRElORVNTX1NUQVRFX0xJTUlUX1JFQUNIRUQQBBIqCiZNT0RFTF9SRUFESU5FU1NfU1RBVEVfQUNDRVNTX1NVU1BFTkRFRBAFEjEKLU1PREVMX1JFQURJTkVTU19TVEFURV9URU1QT1JBUklMWV9VTkFWQUlMQUJMRRAGKqIBCg9Nb2RlbE5leHRBY3Rpb24SIQodTU9ERUxfTkVYVF9BQ1RJT05fVU5TUEVDSUZJRUQQABIrCidNT0RFTF9ORVhUX0FDVElPTl9DT05UQUNUX0FETUlOSVNUUkFUT1IQARIiCh5NT0RFTF9ORVhUX0FDVElPTl9WSUVXX0ZVTkRJTkcQAhIbChdNT0RFTF9ORVhUX0FDVElPTl9SRVRSWRADKnkKD0NsaWVudFJ1bGVTY29wZRIhCh1DTElFTlRfUlVMRV9TQ09QRV9VTlNQRUNJRklFRBAAEiIKHkNMSUVOVF9SVUxFX1NDT1BFX09SR0FOSVpBVElPThABEh8KG0NMSUVOVF9SVUxFX1NDT1BFX1dPUktTUEFDRRACKocBCg1DbGllbnRNY3BNb2RlEh8KG0NMSUVOVF9NQ1BfTU9ERV9VTlNQRUNJRklFRBAAEhgKFENMSUVOVF9NQ1BfTU9ERV9PUEVOEAESHQoZQ0xJRU5UX01DUF9NT0RFX0FMTE9XTElTVBACEhwKGENMSUVOVF9NQ1BfTU9ERV9ERU5ZTElTVBADKtQBCg5SZXNwb25zZUFjdGlvbhIfChtSRVNQT05TRV9BQ1RJT05fVU5TUEVDSUZJRUQQABIbChdSRVNQT05TRV9BQ1RJT05fQVBQUk9WRRABEhgKFFJFU1BPTlNFX0FDVElPTl9ERU5ZEAISGgoWUkVTUE9OU0VfQUNUSU9OX0FOU1dFUhADEhkKFVJFU1BPTlNFX0FDVElPTl9SRVRSWRAEEhgKFFJFU1BPTlNFX0FDVElPTl9TS0lQEAUSGQoVUkVTUE9OU0VfQUNUSU9OX0FCT1JUEAYypQ4KE0RlaXhpY1B1YmxpY1NlcnZpY2USUgoJR2V0VGhyZWFkEiEuZGVpeGljcHVibGljLnYxLkdldFRocmVhZFJlcXVlc3QaIi5kZWl4aWNwdWJsaWMudjEuR2V0VGhyZWFkUmVzcG9uc2USWAoLTGlzdFRocmVhZHMSIy5kZWl4aWNwdWJsaWMudjEuTGlzdFRocmVhZHNSZXF1ZXN0GiQuZGVpeGljcHVibGljLnYxLkxpc3RUaHJlYWRzUmVzcG9uc2USWwoMUmVuYW1lVGhyZWFkEiQuZGVpeGljcHVibGljLnYxLlJlbmFtZVRocmVhZFJlcXVlc3QaJS5kZWl4aWNwdWJsaWMudjEuUmVuYW1lVGhyZWFkUmVzcG9uc2USXgoNQXJjaGl2ZVRocmVhZBIlLmRlaXhpY3B1YmxpYy52MS5BcmNoaXZlVGhyZWFkUmVxdWVzdBomLmRlaXhpY3B1YmxpYy52MS5BcmNoaXZlVGhyZWFkUmVzcG9uc2USVQoKTGlzdEV2ZW50cxIiLmRlaXhpY3B1YmxpYy52MS5MaXN0RXZlbnRzUmVxdWVzdBojLmRlaXhpY3B1YmxpYy52MS5MaXN0RXZlbnRzUmVzcG9uc2USWgoLV2F0Y2hFdmVudHMSIy5kZWl4aWNwdWJsaWMudjEuV2F0Y2hFdmVudHNSZXF1ZXN0GiQuZGVpeGljcHVibGljLnYxLldhdGNoRXZlbnRzUmVzcG9uc2UwARJVCgpTdWJtaXRUYXNrEiIuZGVpeGljcHVibGljLnYxLlN1Ym1pdFRhc2tSZXF1ZXN0GiMuZGVpeGljcHVibGljLnYxLlN1Ym1pdFRhc2tSZXNwb25zZRJeCg1JbnRlcnJ1cHRUYXNrEiUuZGVpeGljcHVibGljLnYxLkludGVycnVwdFRhc2tSZXF1ZXN0GiYuZGVpeGljcHVibGljLnYxLkludGVycnVwdFRhc2tSZXNwb25zZRJnChBSZXNwb25kVG9SZXF1ZXN0EiguZGVpeGljcHVibGljLnYxLlJlc3BvbmRUb1JlcXVlc3RSZXF1ZXN0GikuZGVpeGljcHVibGljLnYxLlJlc3BvbmRUb1JlcXVlc3RSZXNwb25zZRJVCgpHZXRSZWNlaXB0EiIuZGVpeGljcHVibGljLnYxLkdldFJlY2VpcHRSZXF1ZXN0GiMuZGVpeGljcHVibGljLnYxLkdldFJlY2VpcHRSZXNwb25zZRJzChRSZXNvbHZlUmVjZWlwdEFjdGlvbhIsLmRlaXhpY3B1YmxpYy52MS5SZXNvbHZlUmVjZWlwdEFjdGlvblJlcXVlc3QaLS5kZWl4aWNwdWJsaWMudjEuUmVzb2x2ZVJlY2VpcHRBY3Rpb25SZXNwb25zZRJqChFHZXRNb2RlbFJlYWRpbmVzcxIpLmRlaXhpY3B1YmxpYy52MS5HZXRNb2RlbFJlYWRpbmVzc1JlcXVlc3QaKi5kZWl4aWNwdWJsaWMudjEuR2V0TW9kZWxSZWFkaW5lc3NSZXNwb25zZRJhCg5HZXRDbGllbnRTZXR1cBImLmRlaXhpY3B1YmxpYy52MS5HZXRDbGllbnRTZXR1cFJlcXVlc3QaJy5kZWl4aWNwdWJsaWMudjEuR2V0Q2xpZW50U2V0dXBSZXNwb25zZRJqChFTdWJtaXRJc3N1ZVJlcG9ydBIpLmRlaXhpY3B1YmxpYy52MS5TdWJtaXRJc3N1ZVJlcG9ydFJlcXVlc3QaKi5kZWl4aWNwdWJsaWMudjEuU3VibWl0SXNzdWVSZXBvcnRSZXNwb25zZRJzChRDcmVhdGVCdXNpbmVzc09iamVjdBIsLmRlaXhpY3B1YmxpYy52MS5DcmVhdGVCdXNpbmVzc09iamVjdFJlcXVlc3QaLS5kZWl4aWNwdWJsaWMudjEuQ3JlYXRlQnVzaW5lc3NPYmplY3RSZXNwb25zZRJqChFHZXRCdXNpbmVzc09iamVjdBIpLmRlaXhpY3B1YmxpYy52MS5HZXRCdXNpbmVzc09iamVjdFJlcXVlc3QaKi5kZWl4aWNwdWJsaWMudjEuR2V0QnVzaW5lc3NPYmplY3RSZXNwb25zZRJzChRVcGRhdGVCdXNpbmVzc09iamVjdBIsLmRlaXhpY3B1YmxpYy52MS5VcGRhdGVCdXNpbmVzc09iamVjdFJlcXVlc3QaLS5kZWl4aWNwdWJsaWMudjEuVXBkYXRlQnVzaW5lc3NPYmplY3RSZXNwb25zZRJzChREZWxldGVCdXNpbmVzc09iamVjdBIsLmRlaXhpY3B1YmxpYy52MS5EZWxldGVCdXNpbmVzc09iamVjdFJlcXVlc3QaLS5kZWl4aWNwdWJsaWMudjEuRGVsZXRlQnVzaW5lc3NPYmplY3RSZXNwb25zZUI9WjtnaXRodWIuY29tL2R4LWNvcnAvZGVpeGljLWdvL2RlaXhpY3B1YmxpYy92MTtkZWl4aWNwdWJsaWN2MWIGcHJvdG8z", [file_google_protobuf_timestamp]); + +/** + * @generated from message deixicpublic.v1.Scope + */ +export type Scope = Message<"deixicpublic.v1.Scope"> & { + /** + * @generated from field: string organization_id = 1; + */ + organizationId: string; + + /** + * @generated from field: string workspace_id = 2; + */ + workspaceId: string; +}; + +/** + * Describes the message deixicpublic.v1.Scope. + * Use `create(ScopeSchema)` to create a new message. + */ +export const ScopeSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 0); + +/** + * @generated from message deixicpublic.v1.ErrorDetail + */ +export type ErrorDetail = Message<"deixicpublic.v1.ErrorDetail"> & { + /** + * @generated from field: string code = 1; + */ + code: string; + + /** + * @generated from field: string message = 2; + */ + message: string; + + /** + * @generated from field: string request_id = 3; + */ + requestId: string; + + /** + * @generated from field: bool retryable = 4; + */ + retryable: boolean; +}; + +/** + * Describes the message deixicpublic.v1.ErrorDetail. + * Use `create(ErrorDetailSchema)` to create a new message. + */ +export const ErrorDetailSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 1); + +/** + * @generated from message deixicpublic.v1.TaskTurn + */ +export type TaskTurn = Message<"deixicpublic.v1.TaskTurn"> & { + /** + * @generated from field: string turn_id = 1; + */ + turnId: string; + + /** + * @generated from field: int64 sequence = 2; + */ + sequence: bigint; + + /** + * @generated from field: string user_message_id = 3; + */ + userMessageId: string; + + /** + * @generated from field: string assistant_message_id = 4; + */ + assistantMessageId: string; + + /** + * @generated from field: deixicpublic.v1.TurnState state = 5; + */ + state: TurnState; + + /** + * @generated from field: deixicpublic.v1.WaitingReason waiting_reason = 6; + */ + waitingReason: WaitingReason; + + /** + * @generated from field: int64 first_cursor = 7; + */ + firstCursor: bigint; + + /** + * @generated from field: int64 last_cursor = 8; + */ + lastCursor: bigint; + + /** + * @generated from field: deixicpublic.v1.ErrorDetail terminal_error = 9; + */ + terminalError?: ErrorDetail | undefined; + + /** + * @generated from field: google.protobuf.Timestamp created_at = 10; + */ + createdAt?: Timestamp | undefined; + + /** + * @generated from field: google.protobuf.Timestamp updated_at = 11; + */ + updatedAt?: Timestamp | undefined; + + /** + * @generated from field: google.protobuf.Timestamp completed_at = 12; + */ + completedAt?: Timestamp | undefined; +}; + +/** + * Describes the message deixicpublic.v1.TaskTurn. + * Use `create(TaskTurnSchema)` to create a new message. + */ +export const TaskTurnSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 2); + +/** + * @generated from message deixicpublic.v1.Thread + */ +export type Thread = Message<"deixicpublic.v1.Thread"> & { + /** + * @generated from field: string id = 1; + */ + id: string; + + /** + * @generated from field: string title = 2; + */ + title: string; + + /** + * @generated from field: int64 replay_cursor = 3; + */ + replayCursor: bigint; + + /** + * @generated from field: int64 active_turn_sequence = 4; + */ + activeTurnSequence: bigint; + + /** + * @generated from field: google.protobuf.Timestamp updated_at = 5; + */ + updatedAt?: Timestamp | undefined; + + /** + * @generated from field: int32 unread_count = 6; + */ + unreadCount: number; + + /** + * @generated from field: int32 open_count = 7; + */ + openCount: number; + + /** + * @generated from field: bool archived = 8; + */ + archived: boolean; +}; + +/** + * Describes the message deixicpublic.v1.Thread. + * Use `create(ThreadSchema)` to create a new message. + */ +export const ThreadSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 3); + +/** + * @generated from message deixicpublic.v1.TaskMessage + */ +export type TaskMessage = Message<"deixicpublic.v1.TaskMessage"> & { + /** + * @generated from field: string id = 1; + */ + id: string; + + /** + * @generated from field: deixicpublic.v1.MessageRole role = 2; + */ + role: MessageRole; + + /** + * @generated from field: string body = 3; + */ + body: string; + + /** + * @generated from field: google.protobuf.Timestamp created_at = 4; + */ + createdAt?: Timestamp | undefined; + + /** + * @generated from field: repeated string receipt_ids = 5; + */ + receiptIds: string[]; +}; + +/** + * Describes the message deixicpublic.v1.TaskMessage. + * Use `create(TaskMessageSchema)` to create a new message. + */ +export const TaskMessageSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 4); + +/** + * @generated from message deixicpublic.v1.EvidenceReference + */ +export type EvidenceReference = Message<"deixicpublic.v1.EvidenceReference"> & { + /** + * @generated from field: string kind = 1; + */ + kind: string; + + /** + * @generated from field: string id = 2; + */ + id: string; + + /** + * @generated from field: string label = 3; + */ + label: string; + + /** + * @generated from field: string uri = 4; + */ + uri: string; +}; + +/** + * Describes the message deixicpublic.v1.EvidenceReference. + * Use `create(EvidenceReferenceSchema)` to create a new message. + */ +export const EvidenceReferenceSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 5); + +/** + * @generated from message deixicpublic.v1.TaskEvent + */ +export type TaskEvent = Message<"deixicpublic.v1.TaskEvent"> & { + /** + * @generated from field: int64 cursor = 1; + */ + cursor: bigint; + + /** + * @generated from field: string id = 2; + */ + id: string; + + /** + * @generated from field: string turn_id = 3; + */ + turnId: string; + + /** + * @generated from field: deixicpublic.v1.EventKind kind = 4; + */ + kind: EventKind; + + /** + * @generated from field: string text = 5; + */ + text: string; + + /** + * @generated from field: repeated deixicpublic.v1.EvidenceReference evidence = 6; + */ + evidence: EvidenceReference[]; + + /** + * @generated from field: google.protobuf.Timestamp created_at = 7; + */ + createdAt?: Timestamp | undefined; + + /** + * @generated from field: string request_id = 8; + */ + requestId: string; + + /** + * @generated from field: deixicpublic.v1.RequestKind request_kind = 9; + */ + requestKind: RequestKind; + + /** + * @generated from field: string tool_name = 10; + */ + toolName: string; + + /** + * @generated from field: string call_id = 11; + */ + callId: string; + + /** + * @generated from field: deixicpublic.v1.ErrorDetail terminal_error = 12; + */ + terminalError?: ErrorDetail | undefined; +}; + +/** + * Describes the message deixicpublic.v1.TaskEvent. + * Use `create(TaskEventSchema)` to create a new message. + */ +export const TaskEventSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 6); + +/** + * @generated from message deixicpublic.v1.ReceiptAction + */ +export type ReceiptAction = Message<"deixicpublic.v1.ReceiptAction"> & { + /** + * @generated from field: string id = 1; + */ + id: string; + + /** + * @generated from field: string label = 2; + */ + label: string; + + /** + * @generated from field: string kind = 3; + */ + kind: string; + + /** + * @generated from field: bool requires_confirmation = 4; + */ + requiresConfirmation: boolean; + + /** + * @generated from field: string disabled_reason = 5; + */ + disabledReason: string; +}; + +/** + * Describes the message deixicpublic.v1.ReceiptAction. + * Use `create(ReceiptActionSchema)` to create a new message. + */ +export const ReceiptActionSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 7); + +/** + * @generated from message deixicpublic.v1.CodingOutput + */ +export type CodingOutput = Message<"deixicpublic.v1.CodingOutput"> & { + /** + * @generated from field: string path = 1; + */ + path: string; + + /** + * @generated from field: string object_id = 2; + */ + objectId: string; + + /** + * @generated from field: string version_id = 3; + */ + versionId: string; + + /** + * @generated from field: string sha256 = 4; + */ + sha256: string; + + /** + * @generated from field: uint64 size_bytes = 5; + */ + sizeBytes: bigint; + + /** + * Included only in an explicitly requested receipt read by the authorized actor. + * + * @generated from field: bytes content = 6; + */ + content: Uint8Array; +}; + +/** + * Describes the message deixicpublic.v1.CodingOutput. + * Use `create(CodingOutputSchema)` to create a new message. + */ +export const CodingOutputSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 8); + +/** + * @generated from message deixicpublic.v1.CodingAcceptance + */ +export type CodingAcceptance = Message<"deixicpublic.v1.CodingAcceptance"> & { + /** + * @generated from field: bool accepted = 1; + */ + accepted: boolean; + + /** + * @generated from field: string contract_digest = 2; + */ + contractDigest: string; + + /** + * @generated from field: string submission_digest = 3; + */ + submissionDigest: string; + + /** + * @generated from field: repeated string reasons = 4; + */ + reasons: string[]; + + /** + * @generated from field: string revision = 5; + */ + revision: string; + + /** + * @generated from field: repeated deixicpublic.v1.CodingOutput outputs = 6; + */ + outputs: CodingOutput[]; +}; + +/** + * Describes the message deixicpublic.v1.CodingAcceptance. + * Use `create(CodingAcceptanceSchema)` to create a new message. + */ +export const CodingAcceptanceSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 9); + +/** + * @generated from message deixicpublic.v1.Receipt + */ +export type Receipt = Message<"deixicpublic.v1.Receipt"> & { + /** + * @generated from field: string id = 1; + */ + id: string; + + /** + * @generated from field: string kind = 2; + */ + kind: string; + + /** + * @generated from field: string title = 3; + */ + title: string; + + /** + * @generated from field: string summary = 4; + */ + summary: string; + + /** + * @generated from field: deixicpublic.v1.ReceiptState state = 5; + */ + state: ReceiptState; + + /** + * @generated from field: google.protobuf.Timestamp updated_at = 6; + */ + updatedAt?: Timestamp | undefined; + + /** + * @generated from field: repeated deixicpublic.v1.ReceiptAction allowed_actions = 7; + */ + allowedActions: ReceiptAction[]; + + /** + * @generated from field: repeated deixicpublic.v1.EvidenceReference evidence = 8; + */ + evidence: EvidenceReference[]; + + /** + * @generated from field: deixicpublic.v1.CodingAcceptance coding_acceptance = 9; + */ + codingAcceptance?: CodingAcceptance | undefined; +}; + +/** + * Describes the message deixicpublic.v1.Receipt. + * Use `create(ReceiptSchema)` to create a new message. + */ +export const ReceiptSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 10); + +/** + * @generated from message deixicpublic.v1.ModelSelection + */ +export type ModelSelection = Message<"deixicpublic.v1.ModelSelection"> & { + /** + * @generated from field: string provider = 1; + */ + provider: string; + + /** + * @generated from field: string model = 2; + */ + model: string; +}; + +/** + * Describes the message deixicpublic.v1.ModelSelection. + * Use `create(ModelSelectionSchema)` to create a new message. + */ +export const ModelSelectionSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 11); + +/** + * @generated from message deixicpublic.v1.AvailableModel + */ +export type AvailableModel = Message<"deixicpublic.v1.AvailableModel"> & { + /** + * @generated from field: string provider = 1; + */ + provider: string; + + /** + * @generated from field: string model = 2; + */ + model: string; + + /** + * @generated from field: bool ready = 3; + */ + ready: boolean; + + /** + * @generated from field: string display_name = 4; + */ + displayName: string; +}; + +/** + * Describes the message deixicpublic.v1.AvailableModel. + * Use `create(AvailableModelSchema)` to create a new message. + */ +export const AvailableModelSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 12); + +/** + * @generated from message deixicpublic.v1.SetupReadiness + */ +export type SetupReadiness = Message<"deixicpublic.v1.SetupReadiness"> & { + /** + * @generated from field: bool accessible = 1; + */ + accessible: boolean; + + /** + * @generated from field: repeated string missing_requirements = 2; + */ + missingRequirements: string[]; + + /** + * @generated from field: deixicpublic.v1.ModelSelection selection = 3; + */ + selection?: ModelSelection | undefined; + + /** + * @generated from field: deixicpublic.v1.AvailableModel default_model = 4; + */ + defaultModel?: AvailableModel | undefined; + + /** + * @generated from field: repeated deixicpublic.v1.AvailableModel available_models = 5; + */ + availableModels: AvailableModel[]; + + /** + * @generated from field: string next_action = 6; + */ + nextAction: string; +}; + +/** + * Describes the message deixicpublic.v1.SetupReadiness. + * Use `create(SetupReadinessSchema)` to create a new message. + */ +export const SetupReadinessSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 13); + +/** + * @generated from message deixicpublic.v1.GetModelReadinessRequest + */ +export type GetModelReadinessRequest = Message<"deixicpublic.v1.GetModelReadinessRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: deixicpublic.v1.ModelSelection selection = 2; + */ + selection?: ModelSelection | undefined; + + /** + * @generated from field: string environment = 3; + */ + environment: string; +}; + +/** + * Describes the message deixicpublic.v1.GetModelReadinessRequest. + * Use `create(GetModelReadinessRequestSchema)` to create a new message. + */ +export const GetModelReadinessRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 14); + +/** + * @generated from message deixicpublic.v1.GetModelReadinessResponse + */ +export type GetModelReadinessResponse = Message<"deixicpublic.v1.GetModelReadinessResponse"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: deixicpublic.v1.ModelSelection selection = 2; + */ + selection?: ModelSelection | undefined; + + /** + * @generated from field: string environment = 3; + */ + environment: string; + + /** + * @generated from field: deixicpublic.v1.ModelReadinessState state = 4; + */ + state: ModelReadinessState; + + /** + * @generated from field: repeated deixicpublic.v1.ModelNextAction next_actions = 5; + */ + nextActions: ModelNextAction[]; + + /** + * @generated from field: google.protobuf.Timestamp evaluated_at = 6; + */ + evaluatedAt?: Timestamp | undefined; +}; + +/** + * Describes the message deixicpublic.v1.GetModelReadinessResponse. + * Use `create(GetModelReadinessResponseSchema)` to create a new message. + */ +export const GetModelReadinessResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 15); + +/** + * @generated from message deixicpublic.v1.ClientRule + */ +export type ClientRule = Message<"deixicpublic.v1.ClientRule"> & { + /** + * @generated from field: string id = 1; + */ + id: string; + + /** + * @generated from field: string title = 2; + */ + title: string; + + /** + * @generated from field: string body_markdown = 3; + */ + bodyMarkdown: string; + + /** + * @generated from field: deixicpublic.v1.ClientRuleScope scope = 4; + */ + scope: ClientRuleScope; +}; + +/** + * Describes the message deixicpublic.v1.ClientRule. + * Use `create(ClientRuleSchema)` to create a new message. + */ +export const ClientRuleSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 16); + +/** + * @generated from message deixicpublic.v1.ClientSkill + */ +export type ClientSkill = Message<"deixicpublic.v1.ClientSkill"> & { + /** + * @generated from field: string id = 1; + */ + id: string; + + /** + * @generated from field: string source = 2; + */ + source: string; + + /** + * @generated from field: string version = 3; + */ + version: string; + + /** + * @generated from field: bool required = 4; + */ + required: boolean; +}; + +/** + * Describes the message deixicpublic.v1.ClientSkill. + * Use `create(ClientSkillSchema)` to create a new message. + */ +export const ClientSkillSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 17); + +/** + * @generated from message deixicpublic.v1.ClientMcpServer + */ +export type ClientMcpServer = Message<"deixicpublic.v1.ClientMcpServer"> & { + /** + * @generated from field: string name = 1; + */ + name: string; + + /** + * @generated from field: string url_pattern = 2; + */ + urlPattern: string; + + /** + * @generated from field: string transport = 3; + */ + transport: string; +}; + +/** + * Describes the message deixicpublic.v1.ClientMcpServer. + * Use `create(ClientMcpServerSchema)` to create a new message. + */ +export const ClientMcpServerSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 18); + +/** + * @generated from message deixicpublic.v1.ClientMcpPolicy + */ +export type ClientMcpPolicy = Message<"deixicpublic.v1.ClientMcpPolicy"> & { + /** + * @generated from field: deixicpublic.v1.ClientMcpMode mode = 1; + */ + mode: ClientMcpMode; + + /** + * @generated from field: repeated deixicpublic.v1.ClientMcpServer servers = 2; + */ + servers: ClientMcpServer[]; +}; + +/** + * Describes the message deixicpublic.v1.ClientMcpPolicy. + * Use `create(ClientMcpPolicySchema)` to create a new message. + */ +export const ClientMcpPolicySchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 19); + +/** + * @generated from message deixicpublic.v1.GetClientSetupRequest + */ +export type GetClientSetupRequest = Message<"deixicpublic.v1.GetClientSetupRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; +}; + +/** + * Describes the message deixicpublic.v1.GetClientSetupRequest. + * Use `create(GetClientSetupRequestSchema)` to create a new message. + */ +export const GetClientSetupRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 20); + +/** + * @generated from message deixicpublic.v1.GetClientSetupResponse + */ +export type GetClientSetupResponse = Message<"deixicpublic.v1.GetClientSetupResponse"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: uint64 version = 2; + */ + version: bigint; + + /** + * @generated from field: google.protobuf.Timestamp issued_at = 3; + */ + issuedAt?: Timestamp | undefined; + + /** + * @generated from field: repeated deixicpublic.v1.ClientRule rules = 4; + */ + rules: ClientRule[]; + + /** + * @generated from field: repeated deixicpublic.v1.ClientSkill skills = 5; + */ + skills: ClientSkill[]; + + /** + * @generated from field: deixicpublic.v1.ClientMcpPolicy mcp = 6; + */ + mcp?: ClientMcpPolicy | undefined; + + /** + * @generated from field: string sandbox_policy_toml = 7; + */ + sandboxPolicyToml: string; +}; + +/** + * Describes the message deixicpublic.v1.GetClientSetupResponse. + * Use `create(GetClientSetupResponseSchema)` to create a new message. + */ +export const GetClientSetupResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 21); + +/** + * @generated from message deixicpublic.v1.IssueEvidence + */ +export type IssueEvidence = Message<"deixicpublic.v1.IssueEvidence"> & { + /** + * @generated from field: string kind = 1; + */ + kind: string; + + /** + * @generated from field: string source_id = 2; + */ + sourceId: string; + + /** + * @generated from field: string text = 3; + */ + text: string; +}; + +/** + * Describes the message deixicpublic.v1.IssueEvidence. + * Use `create(IssueEvidenceSchema)` to create a new message. + */ +export const IssueEvidenceSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 22); + +/** + * @generated from message deixicpublic.v1.IssueContext + */ +export type IssueContext = Message<"deixicpublic.v1.IssueContext"> & { + /** + * @generated from field: string reproduction_steps = 1; + */ + reproductionSteps: string; + + /** + * @generated from field: string model = 2; + */ + model: string; + + /** + * @generated from field: repeated deixicpublic.v1.IssueEvidence evidence = 3; + */ + evidence: IssueEvidence[]; +}; + +/** + * Describes the message deixicpublic.v1.IssueContext. + * Use `create(IssueContextSchema)` to create a new message. + */ +export const IssueContextSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 23); + +/** + * @generated from message deixicpublic.v1.SubmitIssueReportRequest + */ +export type SubmitIssueReportRequest = Message<"deixicpublic.v1.SubmitIssueReportRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: string description = 2; + */ + description: string; + + /** + * @generated from field: string expected_behavior = 3; + */ + expectedBehavior: string; + + /** + * @generated from field: string app_version = 4; + */ + appVersion: string; + + /** + * @generated from field: bool include_diagnostics = 5; + */ + includeDiagnostics: boolean; + + /** + * @generated from field: string idempotency_key = 6; + */ + idempotencyKey: string; + + /** + * @generated from field: deixicpublic.v1.IssueContext context = 7; + */ + context?: IssueContext | undefined; +}; + +/** + * Describes the message deixicpublic.v1.SubmitIssueReportRequest. + * Use `create(SubmitIssueReportRequestSchema)` to create a new message. + */ +export const SubmitIssueReportRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 24); + +/** + * @generated from message deixicpublic.v1.IssueReport + */ +export type IssueReport = Message<"deixicpublic.v1.IssueReport"> & { + /** + * @generated from field: string id = 1; + */ + id: string; + + /** + * @generated from field: string reference = 2; + */ + reference: string; +}; + +/** + * Describes the message deixicpublic.v1.IssueReport. + * Use `create(IssueReportSchema)` to create a new message. + */ +export const IssueReportSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 25); + +/** + * @generated from message deixicpublic.v1.SubmitIssueReportResponse + */ +export type SubmitIssueReportResponse = Message<"deixicpublic.v1.SubmitIssueReportResponse"> & { + /** + * @generated from field: deixicpublic.v1.IssueReport report = 1; + */ + report?: IssueReport | undefined; +}; + +/** + * Describes the message deixicpublic.v1.SubmitIssueReportResponse. + * Use `create(SubmitIssueReportResponseSchema)` to create a new message. + */ +export const SubmitIssueReportResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 26); + +/** + * This resource is the supported Terraform provider contract. Source authority, + * connector state and recovery coordinates belong to the implementation. + * + * @generated from message deixicpublic.v1.BusinessMoney + */ +export type BusinessMoney = Message<"deixicpublic.v1.BusinessMoney"> & { + /** + * @generated from field: string amount = 1; + */ + amount: string; + + /** + * @generated from field: string currency = 2; + */ + currency: string; +}; + +/** + * Describes the message deixicpublic.v1.BusinessMoney. + * Use `create(BusinessMoneySchema)` to create a new message. + */ +export const BusinessMoneySchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 27); + +/** + * @generated from message deixicpublic.v1.BusinessObjectReference + */ +export type BusinessObjectReference = Message<"deixicpublic.v1.BusinessObjectReference"> & { + /** + * @generated from field: string object_id = 1; + */ + objectId: string; +}; + +/** + * Describes the message deixicpublic.v1.BusinessObjectReference. + * Use `create(BusinessObjectReferenceSchema)` to create a new message. + */ +export const BusinessObjectReferenceSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 28); + +/** + * @generated from message deixicpublic.v1.BusinessArtifactReference + */ +export type BusinessArtifactReference = Message<"deixicpublic.v1.BusinessArtifactReference"> & { + /** + * @generated from field: string artifact_version_id = 1; + */ + artifactVersionId: string; +}; + +/** + * Describes the message deixicpublic.v1.BusinessArtifactReference. + * Use `create(BusinessArtifactReferenceSchema)` to create a new message. + */ +export const BusinessArtifactReferenceSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 29); + +/** + * @generated from message deixicpublic.v1.BusinessTextList + */ +export type BusinessTextList = Message<"deixicpublic.v1.BusinessTextList"> & { + /** + * @generated from field: repeated string values = 1; + */ + values: string[]; +}; + +/** + * Describes the message deixicpublic.v1.BusinessTextList. + * Use `create(BusinessTextListSchema)` to create a new message. + */ +export const BusinessTextListSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 30); + +/** + * @generated from message deixicpublic.v1.BusinessFieldValue + */ +export type BusinessFieldValue = Message<"deixicpublic.v1.BusinessFieldValue"> & { + /** + * @generated from field: string field_id = 1; + */ + fieldId: string; + + /** + * @generated from oneof deixicpublic.v1.BusinessFieldValue.value + */ + value: { + /** + * @generated from field: string text = 2; + */ + value: string; + case: "text"; + } | { + /** + * @generated from field: int64 integer = 3; + */ + value: bigint; + case: "integer"; + } | { + /** + * @generated from field: bool boolean = 4; + */ + value: boolean; + case: "boolean"; + } | { + /** + * @generated from field: string decimal = 5; + */ + value: string; + case: "decimal"; + } | { + /** + * @generated from field: deixicpublic.v1.BusinessMoney money = 6; + */ + value: BusinessMoney; + case: "money"; + } | { + /** + * @generated from field: string enum_value = 7; + */ + value: string; + case: "enumValue"; + } | { + /** + * @generated from field: string date = 8; + */ + value: string; + case: "date"; + } | { + /** + * @generated from field: string timestamp = 9; + */ + value: string; + case: "timestamp"; + } | { + /** + * @generated from field: deixicpublic.v1.BusinessObjectReference reference = 10; + */ + value: BusinessObjectReference; + case: "reference"; + } | { + /** + * @generated from field: deixicpublic.v1.BusinessArtifactReference artifact = 11; + */ + value: BusinessArtifactReference; + case: "artifact"; + } | { + /** + * @generated from field: deixicpublic.v1.BusinessTextList text_list = 12; + */ + value: BusinessTextList; + case: "textList"; + } | { case: undefined; value?: undefined }; +}; + +/** + * Describes the message deixicpublic.v1.BusinessFieldValue. + * Use `create(BusinessFieldValueSchema)` to create a new message. + */ +export const BusinessFieldValueSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 31); + +/** + * @generated from message deixicpublic.v1.BusinessObject + */ +export type BusinessObject = Message<"deixicpublic.v1.BusinessObject"> & { + /** + * @generated from field: string object_id = 1; + */ + objectId: string; + + /** + * @generated from field: string type_id = 2; + */ + typeId: string; + + /** + * @generated from field: int64 schema_revision = 3; + */ + schemaRevision: bigint; + + /** + * @generated from field: int64 revision = 4; + */ + revision: bigint; + + /** + * @generated from field: repeated deixicpublic.v1.BusinessFieldValue values = 5; + */ + values: BusinessFieldValue[]; + + /** + * @generated from field: bool deleted = 6; + */ + deleted: boolean; + + /** + * @generated from field: string updated_at = 9; + */ + updatedAt: string; + + /** + * @generated from field: string created_at = 10; + */ + createdAt: string; +}; + +/** + * Describes the message deixicpublic.v1.BusinessObject. + * Use `create(BusinessObjectSchema)` to create a new message. + */ +export const BusinessObjectSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 32); + +/** + * @generated from message deixicpublic.v1.CreateBusinessObjectRequest + */ +export type CreateBusinessObjectRequest = Message<"deixicpublic.v1.CreateBusinessObjectRequest"> & { + /** + * @generated from field: string organization_id = 1; + */ + organizationId: string; + + /** + * @generated from field: string workspace_id = 2; + */ + workspaceId: string; + + /** + * @generated from field: string idempotency_key = 3; + */ + idempotencyKey: string; + + /** + * @generated from field: string type_id = 4; + */ + typeId: string; + + /** + * @generated from field: int64 schema_revision = 5; + */ + schemaRevision: bigint; + + /** + * @generated from field: repeated deixicpublic.v1.BusinessFieldValue values = 6; + */ + values: BusinessFieldValue[]; +}; + +/** + * Describes the message deixicpublic.v1.CreateBusinessObjectRequest. + * Use `create(CreateBusinessObjectRequestSchema)` to create a new message. + */ +export const CreateBusinessObjectRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 33); + +/** + * @generated from message deixicpublic.v1.CreateBusinessObjectResponse + */ +export type CreateBusinessObjectResponse = Message<"deixicpublic.v1.CreateBusinessObjectResponse"> & { + /** + * @generated from field: deixicpublic.v1.BusinessObject object = 1; + */ + object?: BusinessObject | undefined; +}; + +/** + * Describes the message deixicpublic.v1.CreateBusinessObjectResponse. + * Use `create(CreateBusinessObjectResponseSchema)` to create a new message. + */ +export const CreateBusinessObjectResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 34); + +/** + * @generated from message deixicpublic.v1.GetBusinessObjectRequest + */ +export type GetBusinessObjectRequest = Message<"deixicpublic.v1.GetBusinessObjectRequest"> & { + /** + * @generated from field: string organization_id = 1; + */ + organizationId: string; + + /** + * @generated from field: string workspace_id = 2; + */ + workspaceId: string; + + /** + * @generated from field: string object_id = 4; + */ + objectId: string; +}; + +/** + * Describes the message deixicpublic.v1.GetBusinessObjectRequest. + * Use `create(GetBusinessObjectRequestSchema)` to create a new message. + */ +export const GetBusinessObjectRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 35); + +/** + * @generated from message deixicpublic.v1.GetBusinessObjectResponse + */ +export type GetBusinessObjectResponse = Message<"deixicpublic.v1.GetBusinessObjectResponse"> & { + /** + * @generated from field: deixicpublic.v1.BusinessObject object = 1; + */ + object?: BusinessObject | undefined; +}; + +/** + * Describes the message deixicpublic.v1.GetBusinessObjectResponse. + * Use `create(GetBusinessObjectResponseSchema)` to create a new message. + */ +export const GetBusinessObjectResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 36); + +/** + * @generated from message deixicpublic.v1.UpdateBusinessObjectRequest + */ +export type UpdateBusinessObjectRequest = Message<"deixicpublic.v1.UpdateBusinessObjectRequest"> & { + /** + * @generated from field: string organization_id = 1; + */ + organizationId: string; + + /** + * @generated from field: string workspace_id = 2; + */ + workspaceId: string; + + /** + * @generated from field: string idempotency_key = 3; + */ + idempotencyKey: string; + + /** + * @generated from field: string object_id = 4; + */ + objectId: string; + + /** + * @generated from field: int64 expected_revision = 5; + */ + expectedRevision: bigint; + + /** + * @generated from field: repeated deixicpublic.v1.BusinessFieldValue values = 6; + */ + values: BusinessFieldValue[]; + + /** + * @generated from field: int64 schema_revision = 7; + */ + schemaRevision: bigint; +}; + +/** + * Describes the message deixicpublic.v1.UpdateBusinessObjectRequest. + * Use `create(UpdateBusinessObjectRequestSchema)` to create a new message. + */ +export const UpdateBusinessObjectRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 37); + +/** + * @generated from message deixicpublic.v1.UpdateBusinessObjectResponse + */ +export type UpdateBusinessObjectResponse = Message<"deixicpublic.v1.UpdateBusinessObjectResponse"> & { + /** + * @generated from field: deixicpublic.v1.BusinessObject object = 1; + */ + object?: BusinessObject | undefined; +}; + +/** + * Describes the message deixicpublic.v1.UpdateBusinessObjectResponse. + * Use `create(UpdateBusinessObjectResponseSchema)` to create a new message. + */ +export const UpdateBusinessObjectResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 38); + +/** + * @generated from message deixicpublic.v1.DeleteBusinessObjectRequest + */ +export type DeleteBusinessObjectRequest = Message<"deixicpublic.v1.DeleteBusinessObjectRequest"> & { + /** + * @generated from field: string organization_id = 1; + */ + organizationId: string; + + /** + * @generated from field: string workspace_id = 2; + */ + workspaceId: string; + + /** + * @generated from field: string idempotency_key = 3; + */ + idempotencyKey: string; + + /** + * @generated from field: string object_id = 4; + */ + objectId: string; + + /** + * @generated from field: int64 expected_revision = 5; + */ + expectedRevision: bigint; +}; + +/** + * Describes the message deixicpublic.v1.DeleteBusinessObjectRequest. + * Use `create(DeleteBusinessObjectRequestSchema)` to create a new message. + */ +export const DeleteBusinessObjectRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 39); + +/** + * @generated from message deixicpublic.v1.DeleteBusinessObjectResponse + */ +export type DeleteBusinessObjectResponse = Message<"deixicpublic.v1.DeleteBusinessObjectResponse"> & { + /** + * @generated from field: deixicpublic.v1.BusinessObject object = 1; + */ + object?: BusinessObject | undefined; +}; + +/** + * Describes the message deixicpublic.v1.DeleteBusinessObjectResponse. + * Use `create(DeleteBusinessObjectResponseSchema)` to create a new message. + */ +export const DeleteBusinessObjectResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 40); + +/** + * @generated from message deixicpublic.v1.GetThreadRequest + */ +export type GetThreadRequest = Message<"deixicpublic.v1.GetThreadRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: string thread_id = 2; + */ + threadId: string; + + /** + * @generated from field: int32 limit = 3; + */ + limit: number; + + /** + * @generated from field: string page_token = 4; + */ + pageToken: string; +}; + +/** + * Describes the message deixicpublic.v1.GetThreadRequest. + * Use `create(GetThreadRequestSchema)` to create a new message. + */ +export const GetThreadRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 41); + +/** + * @generated from message deixicpublic.v1.GetThreadResponse + */ +export type GetThreadResponse = Message<"deixicpublic.v1.GetThreadResponse"> & { + /** + * @generated from field: deixicpublic.v1.Thread thread = 1; + */ + thread?: Thread | undefined; + + /** + * @generated from field: repeated deixicpublic.v1.TaskMessage messages = 2; + */ + messages: TaskMessage[]; + + /** + * @generated from field: repeated deixicpublic.v1.Receipt receipts = 3; + */ + receipts: Receipt[]; + + /** + * @generated from field: repeated deixicpublic.v1.TaskTurn turns = 4; + */ + turns: TaskTurn[]; + + /** + * @generated from field: int64 replay_cursor = 5; + */ + replayCursor: bigint; + + /** + * @generated from field: string next_page_token = 6; + */ + nextPageToken: string; + + /** + * @generated from field: deixicpublic.v1.SetupReadiness setup = 7; + */ + setup?: SetupReadiness | undefined; +}; + +/** + * Describes the message deixicpublic.v1.GetThreadResponse. + * Use `create(GetThreadResponseSchema)` to create a new message. + */ +export const GetThreadResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 42); + +/** + * @generated from message deixicpublic.v1.ListThreadsRequest + */ +export type ListThreadsRequest = Message<"deixicpublic.v1.ListThreadsRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: bool archived = 2; + */ + archived: boolean; +}; + +/** + * Describes the message deixicpublic.v1.ListThreadsRequest. + * Use `create(ListThreadsRequestSchema)` to create a new message. + */ +export const ListThreadsRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 43); + +/** + * @generated from message deixicpublic.v1.ListThreadsResponse + */ +export type ListThreadsResponse = Message<"deixicpublic.v1.ListThreadsResponse"> & { + /** + * @generated from field: repeated deixicpublic.v1.Thread threads = 1; + */ + threads: Thread[]; +}; + +/** + * Describes the message deixicpublic.v1.ListThreadsResponse. + * Use `create(ListThreadsResponseSchema)` to create a new message. + */ +export const ListThreadsResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 44); + +/** + * @generated from message deixicpublic.v1.RenameThreadRequest + */ +export type RenameThreadRequest = Message<"deixicpublic.v1.RenameThreadRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: string thread_id = 2; + */ + threadId: string; + + /** + * @generated from field: string title = 3; + */ + title: string; +}; + +/** + * Describes the message deixicpublic.v1.RenameThreadRequest. + * Use `create(RenameThreadRequestSchema)` to create a new message. + */ +export const RenameThreadRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 45); + +/** + * @generated from message deixicpublic.v1.RenameThreadResponse + */ +export type RenameThreadResponse = Message<"deixicpublic.v1.RenameThreadResponse"> & { + /** + * @generated from field: deixicpublic.v1.Thread thread = 1; + */ + thread?: Thread | undefined; + + /** + * @generated from field: bool changed = 2; + */ + changed: boolean; +}; + +/** + * Describes the message deixicpublic.v1.RenameThreadResponse. + * Use `create(RenameThreadResponseSchema)` to create a new message. + */ +export const RenameThreadResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 46); + +/** + * @generated from message deixicpublic.v1.ArchiveThreadRequest + */ +export type ArchiveThreadRequest = Message<"deixicpublic.v1.ArchiveThreadRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: string thread_id = 2; + */ + threadId: string; + + /** + * @generated from field: bool archived = 3; + */ + archived: boolean; + + /** + * @generated from field: string idempotency_key = 4; + */ + idempotencyKey: string; +}; + +/** + * Describes the message deixicpublic.v1.ArchiveThreadRequest. + * Use `create(ArchiveThreadRequestSchema)` to create a new message. + */ +export const ArchiveThreadRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 47); + +/** + * @generated from message deixicpublic.v1.ArchiveThreadResponse + */ +export type ArchiveThreadResponse = Message<"deixicpublic.v1.ArchiveThreadResponse"> & { + /** + * @generated from field: deixicpublic.v1.Thread thread = 1; + */ + thread?: Thread | undefined; + + /** + * @generated from field: bool changed = 2; + */ + changed: boolean; + + /** + * @generated from field: bool replayed = 3; + */ + replayed: boolean; +}; + +/** + * Describes the message deixicpublic.v1.ArchiveThreadResponse. + * Use `create(ArchiveThreadResponseSchema)` to create a new message. + */ +export const ArchiveThreadResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 48); + +/** + * @generated from message deixicpublic.v1.ListEventsRequest + */ +export type ListEventsRequest = Message<"deixicpublic.v1.ListEventsRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: string thread_id = 2; + */ + threadId: string; + + /** + * @generated from field: int64 after_cursor = 3; + */ + afterCursor: bigint; + + /** + * @generated from field: int32 limit = 4; + */ + limit: number; +}; + +/** + * Describes the message deixicpublic.v1.ListEventsRequest. + * Use `create(ListEventsRequestSchema)` to create a new message. + */ +export const ListEventsRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 49); + +/** + * @generated from message deixicpublic.v1.ListEventsResponse + */ +export type ListEventsResponse = Message<"deixicpublic.v1.ListEventsResponse"> & { + /** + * @generated from field: repeated deixicpublic.v1.TaskEvent events = 1; + */ + events: TaskEvent[]; + + /** + * @generated from field: int64 next_cursor = 2; + */ + nextCursor: bigint; + + /** + * @generated from field: bool has_more = 3; + */ + hasMore: boolean; + + /** + * @generated from field: bool reset_required = 4; + */ + resetRequired: boolean; + + /** + * @generated from field: deixicpublic.v1.Thread snapshot = 5; + */ + snapshot?: Thread | undefined; + + /** + * @generated from field: repeated deixicpublic.v1.TaskTurn snapshot_turns = 6; + */ + snapshotTurns: TaskTurn[]; +}; + +/** + * Describes the message deixicpublic.v1.ListEventsResponse. + * Use `create(ListEventsResponseSchema)` to create a new message. + */ +export const ListEventsResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 50); + +/** + * @generated from message deixicpublic.v1.WatchEventsRequest + */ +export type WatchEventsRequest = Message<"deixicpublic.v1.WatchEventsRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: string thread_id = 2; + */ + threadId: string; + + /** + * @generated from field: int64 after_cursor = 3; + */ + afterCursor: bigint; +}; + +/** + * Describes the message deixicpublic.v1.WatchEventsRequest. + * Use `create(WatchEventsRequestSchema)` to create a new message. + */ +export const WatchEventsRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 51); + +/** + * @generated from message deixicpublic.v1.WatchEventsResponse + */ +export type WatchEventsResponse = Message<"deixicpublic.v1.WatchEventsResponse"> & { + /** + * @generated from field: repeated deixicpublic.v1.TaskEvent events = 1; + */ + events: TaskEvent[]; + + /** + * @generated from field: int64 next_cursor = 2; + */ + nextCursor: bigint; + + /** + * @generated from field: bool reset_required = 3; + */ + resetRequired: boolean; + + /** + * @generated from field: deixicpublic.v1.Thread snapshot = 4; + */ + snapshot?: Thread | undefined; + + /** + * @generated from field: repeated deixicpublic.v1.TaskTurn snapshot_turns = 5; + */ + snapshotTurns: TaskTurn[]; +}; + +/** + * Describes the message deixicpublic.v1.WatchEventsResponse. + * Use `create(WatchEventsResponseSchema)` to create a new message. + */ +export const WatchEventsResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 52); + +/** + * @generated from message deixicpublic.v1.CodingContract + */ +export type CodingContract = Message<"deixicpublic.v1.CodingContract"> & { + /** + * @generated from field: string repository_id = 1; + */ + repositoryId: string; + + /** + * @generated from field: uint64 generation = 2; + */ + generation: bigint; + + /** + * @generated from field: repeated string required_assertion_ids = 3; + */ + requiredAssertionIds: string[]; + + /** + * @generated from field: bool require_review = 4; + */ + requireReview: boolean; + + /** + * @generated from field: bool require_behavior = 5; + */ + requireBehavior: boolean; + + /** + * @generated from field: repeated string readiness_requirements = 6; + */ + readinessRequirements: string[]; + + /** + * @generated from field: repeated string authorized_skips = 7; + */ + authorizedSkips: string[]; + + /** + * @generated from field: repeated string authorized_dispositions = 8; + */ + authorizedDispositions: string[]; + + /** + * @generated from field: repeated string output_paths = 9; + */ + outputPaths: string[]; +}; + +/** + * Describes the message deixicpublic.v1.CodingContract. + * Use `create(CodingContractSchema)` to create a new message. + */ +export const CodingContractSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 53); + +/** + * @generated from message deixicpublic.v1.SubmitTaskRequest + */ +export type SubmitTaskRequest = Message<"deixicpublic.v1.SubmitTaskRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: string thread_id = 2; + */ + threadId: string; + + /** + * @generated from field: string body = 3; + */ + body: string; + + /** + * @generated from field: string idempotency_key = 4; + */ + idempotencyKey: string; + + /** + * @generated from field: string continuation_task_id = 5; + */ + continuationTaskId: string; + + /** + * @generated from field: repeated string reference_task_ids = 6; + */ + referenceTaskIds: string[]; + + /** + * @generated from field: deixicpublic.v1.ModelSelection model_selection = 7; + */ + modelSelection?: ModelSelection | undefined; + + /** + * @generated from field: deixicpublic.v1.CodingContract coding_contract = 8; + */ + codingContract?: CodingContract | undefined; + + /** + * @generated from field: string project_resource_id = 9; + */ + projectResourceId: string; +}; + +/** + * Describes the message deixicpublic.v1.SubmitTaskRequest. + * Use `create(SubmitTaskRequestSchema)` to create a new message. + */ +export const SubmitTaskRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 54); + +/** + * @generated from message deixicpublic.v1.SubmitTaskResponse + */ +export type SubmitTaskResponse = Message<"deixicpublic.v1.SubmitTaskResponse"> & { + /** + * @generated from field: deixicpublic.v1.TaskMessage message = 1; + */ + message?: TaskMessage | undefined; + + /** + * @generated from field: deixicpublic.v1.TaskTurn accepted_turn = 2; + */ + acceptedTurn?: TaskTurn | undefined; + + /** + * @generated from field: int64 replay_cursor = 3; + */ + replayCursor: bigint; + + /** + * @generated from field: repeated deixicpublic.v1.Receipt receipts = 4; + */ + receipts: Receipt[]; +}; + +/** + * Describes the message deixicpublic.v1.SubmitTaskResponse. + * Use `create(SubmitTaskResponseSchema)` to create a new message. + */ +export const SubmitTaskResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 55); + +/** + * @generated from message deixicpublic.v1.InterruptTaskRequest + */ +export type InterruptTaskRequest = Message<"deixicpublic.v1.InterruptTaskRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: string thread_id = 2; + */ + threadId: string; + + /** + * @generated from field: string turn_id = 3; + */ + turnId: string; + + /** + * @generated from field: string idempotency_key = 4; + */ + idempotencyKey: string; + + /** + * @generated from field: string reason = 5; + */ + reason: string; +}; + +/** + * Describes the message deixicpublic.v1.InterruptTaskRequest. + * Use `create(InterruptTaskRequestSchema)` to create a new message. + */ +export const InterruptTaskRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 56); + +/** + * @generated from message deixicpublic.v1.InterruptTaskResponse + */ +export type InterruptTaskResponse = Message<"deixicpublic.v1.InterruptTaskResponse"> & { + /** + * @generated from field: string turn_id = 1; + */ + turnId: string; + + /** + * @generated from field: bool replayed = 2; + */ + replayed: boolean; + + /** + * @generated from field: repeated deixicpublic.v1.TaskTurn turns = 3; + */ + turns: TaskTurn[]; + + /** + * @generated from field: int64 replay_cursor = 4; + */ + replayCursor: bigint; +}; + +/** + * Describes the message deixicpublic.v1.InterruptTaskResponse. + * Use `create(InterruptTaskResponseSchema)` to create a new message. + */ +export const InterruptTaskResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 57); + +/** + * @generated from message deixicpublic.v1.RespondToRequestRequest + */ +export type RespondToRequestRequest = Message<"deixicpublic.v1.RespondToRequestRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: string thread_id = 2; + */ + threadId: string; + + /** + * @generated from field: string turn_id = 3; + */ + turnId: string; + + /** + * @generated from field: string request_id = 4; + */ + requestId: string; + + /** + * @generated from field: string call_id = 5; + */ + callId: string; + + /** + * @generated from field: deixicpublic.v1.RequestKind request_kind = 6; + */ + requestKind: RequestKind; + + /** + * @generated from field: deixicpublic.v1.ResponseAction action = 7; + */ + action: ResponseAction; + + /** + * @generated from field: string text = 8; + */ + text: string; + + /** + * @generated from field: bool is_error = 9; + */ + isError: boolean; + + /** + * @generated from field: string idempotency_key = 10; + */ + idempotencyKey: string; +}; + +/** + * Describes the message deixicpublic.v1.RespondToRequestRequest. + * Use `create(RespondToRequestRequestSchema)` to create a new message. + */ +export const RespondToRequestRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 58); + +/** + * @generated from message deixicpublic.v1.RespondToRequestResponse + */ +export type RespondToRequestResponse = Message<"deixicpublic.v1.RespondToRequestResponse"> & { + /** + * @generated from field: bool replayed = 1; + */ + replayed: boolean; + + /** + * @generated from field: repeated deixicpublic.v1.TaskTurn turns = 2; + */ + turns: TaskTurn[]; + + /** + * @generated from field: int64 replay_cursor = 3; + */ + replayCursor: bigint; +}; + +/** + * Describes the message deixicpublic.v1.RespondToRequestResponse. + * Use `create(RespondToRequestResponseSchema)` to create a new message. + */ +export const RespondToRequestResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 59); + +/** + * @generated from message deixicpublic.v1.GetReceiptRequest + */ +export type GetReceiptRequest = Message<"deixicpublic.v1.GetReceiptRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: string receipt_id = 2; + */ + receiptId: string; + + /** + * @generated from field: string thread_id = 3; + */ + threadId: string; + + /** + * @generated from field: bool include_coding_output_content = 4; + */ + includeCodingOutputContent: boolean; +}; + +/** + * Describes the message deixicpublic.v1.GetReceiptRequest. + * Use `create(GetReceiptRequestSchema)` to create a new message. + */ +export const GetReceiptRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 60); + +/** + * @generated from message deixicpublic.v1.GetReceiptResponse + */ +export type GetReceiptResponse = Message<"deixicpublic.v1.GetReceiptResponse"> & { + /** + * @generated from field: deixicpublic.v1.Receipt receipt = 1; + */ + receipt?: Receipt | undefined; +}; + +/** + * Describes the message deixicpublic.v1.GetReceiptResponse. + * Use `create(GetReceiptResponseSchema)` to create a new message. + */ +export const GetReceiptResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 61); + +/** + * @generated from message deixicpublic.v1.ResolveReceiptActionRequest + */ +export type ResolveReceiptActionRequest = Message<"deixicpublic.v1.ResolveReceiptActionRequest"> & { + /** + * @generated from field: deixicpublic.v1.Scope scope = 1; + */ + scope?: Scope | undefined; + + /** + * @generated from field: string receipt_id = 2; + */ + receiptId: string; + + /** + * @generated from field: string action_id = 3; + */ + actionId: string; + + /** + * @generated from field: string idempotency_key = 4; + */ + idempotencyKey: string; +}; + +/** + * Describes the message deixicpublic.v1.ResolveReceiptActionRequest. + * Use `create(ResolveReceiptActionRequestSchema)` to create a new message. + */ +export const ResolveReceiptActionRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 62); + +/** + * @generated from message deixicpublic.v1.ResolveReceiptActionResponse + */ +export type ResolveReceiptActionResponse = Message<"deixicpublic.v1.ResolveReceiptActionResponse"> & { + /** + * @generated from field: deixicpublic.v1.Receipt receipt = 1; + */ + receipt?: Receipt | undefined; +}; + +/** + * Describes the message deixicpublic.v1.ResolveReceiptActionResponse. + * Use `create(ResolveReceiptActionResponseSchema)` to create a new message. + */ +export const ResolveReceiptActionResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_deixicpublic_v1_sdk, 63); + +/** + * @generated from enum deixicpublic.v1.TurnState + */ +export enum TurnState { + /** + * @generated from enum value: TURN_STATE_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: TURN_STATE_ACCEPTED = 1; + */ + ACCEPTED = 1, + + /** + * @generated from enum value: TURN_STATE_RUNNING = 2; + */ + RUNNING = 2, + + /** + * @generated from enum value: TURN_STATE_WAITING = 3; + */ + WAITING = 3, + + /** + * @generated from enum value: TURN_STATE_RESPONDED = 4; + */ + RESPONDED = 4, + + /** + * @generated from enum value: TURN_STATE_COMPLETED = 5; + */ + COMPLETED = 5, + + /** + * @generated from enum value: TURN_STATE_FAILED = 6; + */ + FAILED = 6, + + /** + * @generated from enum value: TURN_STATE_INTERRUPTED = 7; + */ + INTERRUPTED = 7, +} + +/** + * Describes the enum deixicpublic.v1.TurnState. + */ +export const TurnStateSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_deixicpublic_v1_sdk, 0); + +/** + * @generated from enum deixicpublic.v1.WaitingReason + */ +export enum WaitingReason { + /** + * @generated from enum value: WAITING_REASON_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: WAITING_REASON_APPROVAL = 1; + */ + APPROVAL = 1, + + /** + * @generated from enum value: WAITING_REASON_USER_INPUT = 2; + */ + USER_INPUT = 2, + + /** + * @generated from enum value: WAITING_REASON_CLIENT_TOOL = 3; + */ + CLIENT_TOOL = 3, + + /** + * @generated from enum value: WAITING_REASON_EXTERNAL_RETRY = 4; + */ + EXTERNAL_RETRY = 4, +} + +/** + * Describes the enum deixicpublic.v1.WaitingReason. + */ +export const WaitingReasonSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_deixicpublic_v1_sdk, 1); + +/** + * @generated from enum deixicpublic.v1.MessageRole + */ +export enum MessageRole { + /** + * @generated from enum value: MESSAGE_ROLE_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: MESSAGE_ROLE_USER = 1; + */ + USER = 1, + + /** + * @generated from enum value: MESSAGE_ROLE_ASSISTANT = 2; + */ + ASSISTANT = 2, + + /** + * @generated from enum value: MESSAGE_ROLE_SYSTEM = 3; + */ + SYSTEM = 3, +} + +/** + * Describes the enum deixicpublic.v1.MessageRole. + */ +export const MessageRoleSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_deixicpublic_v1_sdk, 2); + +/** + * @generated from enum deixicpublic.v1.EventKind + */ +export enum EventKind { + /** + * @generated from enum value: EVENT_KIND_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: EVENT_KIND_TURN_ACCEPTED = 1; + */ + TURN_ACCEPTED = 1, + + /** + * @generated from enum value: EVENT_KIND_TURN_STARTED = 2; + */ + TURN_STARTED = 2, + + /** + * @generated from enum value: EVENT_KIND_PROGRESS = 3; + */ + PROGRESS = 3, + + /** + * @generated from enum value: EVENT_KIND_APPROVAL_REQUIRED = 4; + */ + APPROVAL_REQUIRED = 4, + + /** + * @generated from enum value: EVENT_KIND_INPUT_REQUIRED = 5; + */ + INPUT_REQUIRED = 5, + + /** + * @generated from enum value: EVENT_KIND_ARTIFACT_RECORDED = 6; + */ + ARTIFACT_RECORDED = 6, + + /** + * @generated from enum value: EVENT_KIND_TURN_COMPLETED = 7; + */ + TURN_COMPLETED = 7, + + /** + * @generated from enum value: EVENT_KIND_TURN_FAILED = 8; + */ + TURN_FAILED = 8, + + /** + * @generated from enum value: EVENT_KIND_TURN_INTERRUPTED = 9; + */ + TURN_INTERRUPTED = 9, + + /** + * @generated from enum value: EVENT_KIND_CLIENT_TOOL_REQUIRED = 10; + */ + CLIENT_TOOL_REQUIRED = 10, + + /** + * @generated from enum value: EVENT_KIND_EXTERNAL_RETRY_REQUIRED = 11; + */ + EXTERNAL_RETRY_REQUIRED = 11, +} + +/** + * Describes the enum deixicpublic.v1.EventKind. + */ +export const EventKindSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_deixicpublic_v1_sdk, 3); + +/** + * @generated from enum deixicpublic.v1.RequestKind + */ +export enum RequestKind { + /** + * @generated from enum value: REQUEST_KIND_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: REQUEST_KIND_APPROVAL = 1; + */ + APPROVAL = 1, + + /** + * @generated from enum value: REQUEST_KIND_USER_INPUT = 2; + */ + USER_INPUT = 2, + + /** + * @generated from enum value: REQUEST_KIND_CLIENT_TOOL = 3; + */ + CLIENT_TOOL = 3, + + /** + * @generated from enum value: REQUEST_KIND_EXTERNAL_RETRY = 4; + */ + EXTERNAL_RETRY = 4, +} + +/** + * Describes the enum deixicpublic.v1.RequestKind. + */ +export const RequestKindSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_deixicpublic_v1_sdk, 4); + +/** + * @generated from enum deixicpublic.v1.ReceiptState + */ +export enum ReceiptState { + /** + * @generated from enum value: RECEIPT_STATE_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: RECEIPT_STATE_UNKNOWN = 1; + */ + UNKNOWN = 1, + + /** + * @generated from enum value: RECEIPT_STATE_PROPOSED = 2; + */ + PROPOSED = 2, + + /** + * @generated from enum value: RECEIPT_STATE_QUEUED = 3; + */ + QUEUED = 3, + + /** + * @generated from enum value: RECEIPT_STATE_WAITING_APPROVAL = 4; + */ + WAITING_APPROVAL = 4, + + /** + * @generated from enum value: RECEIPT_STATE_BLOCKED = 5; + */ + BLOCKED = 5, + + /** + * @generated from enum value: RECEIPT_STATE_NEEDS_INPUT = 6; + */ + NEEDS_INPUT = 6, + + /** + * @generated from enum value: RECEIPT_STATE_UNAVAILABLE = 7; + */ + UNAVAILABLE = 7, + + /** + * @generated from enum value: RECEIPT_STATE_RUNNING = 8; + */ + RUNNING = 8, + + /** + * @generated from enum value: RECEIPT_STATE_SUCCEEDED = 9; + */ + SUCCEEDED = 9, + + /** + * @generated from enum value: RECEIPT_STATE_VERIFIED = 10; + */ + VERIFIED = 10, + + /** + * @generated from enum value: RECEIPT_STATE_DENIED = 11; + */ + DENIED = 11, + + /** + * @generated from enum value: RECEIPT_STATE_CANCELLED = 12; + */ + CANCELLED = 12, + + /** + * @generated from enum value: RECEIPT_STATE_FAILED = 13; + */ + FAILED = 13, +} + +/** + * Describes the enum deixicpublic.v1.ReceiptState. + */ +export const ReceiptStateSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_deixicpublic_v1_sdk, 5); + +/** + * Model readiness is an application-level decision; billing and routing + * implementation details stay behind this projection. + * + * @generated from enum deixicpublic.v1.ModelReadinessState + */ +export enum ModelReadinessState { + /** + * @generated from enum value: MODEL_READINESS_STATE_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: MODEL_READINESS_STATE_READY = 1; + */ + READY = 1, + + /** + * @generated from enum value: MODEL_READINESS_STATE_ACTIVATION_REQUIRED = 2; + */ + ACTIVATION_REQUIRED = 2, + + /** + * @generated from enum value: MODEL_READINESS_STATE_FUNDING_REQUIRED = 3; + */ + FUNDING_REQUIRED = 3, + + /** + * @generated from enum value: MODEL_READINESS_STATE_LIMIT_REACHED = 4; + */ + LIMIT_REACHED = 4, + + /** + * @generated from enum value: MODEL_READINESS_STATE_ACCESS_SUSPENDED = 5; + */ + ACCESS_SUSPENDED = 5, + + /** + * @generated from enum value: MODEL_READINESS_STATE_TEMPORARILY_UNAVAILABLE = 6; + */ + TEMPORARILY_UNAVAILABLE = 6, +} + +/** + * Describes the enum deixicpublic.v1.ModelReadinessState. + */ +export const ModelReadinessStateSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_deixicpublic_v1_sdk, 6); + +/** + * @generated from enum deixicpublic.v1.ModelNextAction + */ +export enum ModelNextAction { + /** + * @generated from enum value: MODEL_NEXT_ACTION_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: MODEL_NEXT_ACTION_CONTACT_ADMINISTRATOR = 1; + */ + CONTACT_ADMINISTRATOR = 1, + + /** + * @generated from enum value: MODEL_NEXT_ACTION_VIEW_FUNDING = 2; + */ + VIEW_FUNDING = 2, + + /** + * @generated from enum value: MODEL_NEXT_ACTION_RETRY = 3; + */ + RETRY = 3, +} + +/** + * Describes the enum deixicpublic.v1.ModelNextAction. + */ +export const ModelNextActionSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_deixicpublic_v1_sdk, 7); + +/** + * @generated from enum deixicpublic.v1.ClientRuleScope + */ +export enum ClientRuleScope { + /** + * @generated from enum value: CLIENT_RULE_SCOPE_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: CLIENT_RULE_SCOPE_ORGANIZATION = 1; + */ + ORGANIZATION = 1, + + /** + * @generated from enum value: CLIENT_RULE_SCOPE_WORKSPACE = 2; + */ + WORKSPACE = 2, +} + +/** + * Describes the enum deixicpublic.v1.ClientRuleScope. + */ +export const ClientRuleScopeSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_deixicpublic_v1_sdk, 8); + +/** + * @generated from enum deixicpublic.v1.ClientMcpMode + */ +export enum ClientMcpMode { + /** + * @generated from enum value: CLIENT_MCP_MODE_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: CLIENT_MCP_MODE_OPEN = 1; + */ + OPEN = 1, + + /** + * @generated from enum value: CLIENT_MCP_MODE_ALLOWLIST = 2; + */ + ALLOWLIST = 2, + + /** + * @generated from enum value: CLIENT_MCP_MODE_DENYLIST = 3; + */ + DENYLIST = 3, +} + +/** + * Describes the enum deixicpublic.v1.ClientMcpMode. + */ +export const ClientMcpModeSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_deixicpublic_v1_sdk, 9); + +/** + * @generated from enum deixicpublic.v1.ResponseAction + */ +export enum ResponseAction { + /** + * @generated from enum value: RESPONSE_ACTION_UNSPECIFIED = 0; + */ + UNSPECIFIED = 0, + + /** + * @generated from enum value: RESPONSE_ACTION_APPROVE = 1; + */ + APPROVE = 1, + + /** + * @generated from enum value: RESPONSE_ACTION_DENY = 2; + */ + DENY = 2, + + /** + * @generated from enum value: RESPONSE_ACTION_ANSWER = 3; + */ + ANSWER = 3, + + /** + * @generated from enum value: RESPONSE_ACTION_RETRY = 4; + */ + RETRY = 4, + + /** + * @generated from enum value: RESPONSE_ACTION_SKIP = 5; + */ + SKIP = 5, + + /** + * @generated from enum value: RESPONSE_ACTION_ABORT = 6; + */ + ABORT = 6, +} + +/** + * Describes the enum deixicpublic.v1.ResponseAction. + */ +export const ResponseActionSchema: GenEnum = /*@__PURE__*/ + enumDesc(file_deixicpublic_v1_sdk, 10); + +/** + * This is the complete application SDK wire contract. Public messages are + * projections owned by this service, not aliases of implementation records. + * + * @generated from service deixicpublic.v1.DeixicPublicService + */ +export const DeixicPublicService: GenService<{ + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.GetThread + */ + getThread: { + methodKind: "unary"; + input: typeof GetThreadRequestSchema; + output: typeof GetThreadResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.ListThreads + */ + listThreads: { + methodKind: "unary"; + input: typeof ListThreadsRequestSchema; + output: typeof ListThreadsResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.RenameThread + */ + renameThread: { + methodKind: "unary"; + input: typeof RenameThreadRequestSchema; + output: typeof RenameThreadResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.ArchiveThread + */ + archiveThread: { + methodKind: "unary"; + input: typeof ArchiveThreadRequestSchema; + output: typeof ArchiveThreadResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.ListEvents + */ + listEvents: { + methodKind: "unary"; + input: typeof ListEventsRequestSchema; + output: typeof ListEventsResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.WatchEvents + */ + watchEvents: { + methodKind: "server_streaming"; + input: typeof WatchEventsRequestSchema; + output: typeof WatchEventsResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.SubmitTask + */ + submitTask: { + methodKind: "unary"; + input: typeof SubmitTaskRequestSchema; + output: typeof SubmitTaskResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.InterruptTask + */ + interruptTask: { + methodKind: "unary"; + input: typeof InterruptTaskRequestSchema; + output: typeof InterruptTaskResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.RespondToRequest + */ + respondToRequest: { + methodKind: "unary"; + input: typeof RespondToRequestRequestSchema; + output: typeof RespondToRequestResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.GetReceipt + */ + getReceipt: { + methodKind: "unary"; + input: typeof GetReceiptRequestSchema; + output: typeof GetReceiptResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.ResolveReceiptAction + */ + resolveReceiptAction: { + methodKind: "unary"; + input: typeof ResolveReceiptActionRequestSchema; + output: typeof ResolveReceiptActionResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.GetModelReadiness + */ + getModelReadiness: { + methodKind: "unary"; + input: typeof GetModelReadinessRequestSchema; + output: typeof GetModelReadinessResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.GetClientSetup + */ + getClientSetup: { + methodKind: "unary"; + input: typeof GetClientSetupRequestSchema; + output: typeof GetClientSetupResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.SubmitIssueReport + */ + submitIssueReport: { + methodKind: "unary"; + input: typeof SubmitIssueReportRequestSchema; + output: typeof SubmitIssueReportResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.CreateBusinessObject + */ + createBusinessObject: { + methodKind: "unary"; + input: typeof CreateBusinessObjectRequestSchema; + output: typeof CreateBusinessObjectResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.GetBusinessObject + */ + getBusinessObject: { + methodKind: "unary"; + input: typeof GetBusinessObjectRequestSchema; + output: typeof GetBusinessObjectResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.UpdateBusinessObject + */ + updateBusinessObject: { + methodKind: "unary"; + input: typeof UpdateBusinessObjectRequestSchema; + output: typeof UpdateBusinessObjectResponseSchema; + }, + /** + * @generated from rpc deixicpublic.v1.DeixicPublicService.DeleteBusinessObject + */ + deleteBusinessObject: { + methodKind: "unary"; + input: typeof DeleteBusinessObjectRequestSchema; + output: typeof DeleteBusinessObjectResponseSchema; + }, +}> = /*@__PURE__*/ + serviceDesc(file_deixicpublic_v1_sdk, 0); + + +// SDK compatibility aliases + +export { Scope as ConsoleQuery }; + +export { ScopeSchema as ConsoleQuerySchema }; + +export { GetThreadRequest as GetOperatingThreadRequest }; + +export { GetThreadRequestSchema as GetOperatingThreadRequestSchema }; + +export { GetThreadResponse as GetOperatingThreadResponse }; + +export { GetThreadResponseSchema as GetOperatingThreadResponseSchema }; + +export { ListEventsRequest as ListOperatingThreadEventsRequest }; + +export { ListEventsRequestSchema as ListOperatingThreadEventsRequestSchema }; + +export { ListEventsResponse as ListOperatingThreadEventsResponse }; + +export { ListEventsResponseSchema as ListOperatingThreadEventsResponseSchema }; + +export { WatchEventsRequest as WatchOperatingThreadRequest }; + +export { WatchEventsRequestSchema as WatchOperatingThreadRequestSchema }; + +export { WatchEventsResponse as WatchOperatingThreadResponse }; + +export { WatchEventsResponseSchema as WatchOperatingThreadResponseSchema }; + +export { SubmitTaskRequest as SubmitOperatingMessageRequest }; + +export { SubmitTaskRequestSchema as SubmitOperatingMessageRequestSchema }; + +export { SubmitTaskResponse as SubmitOperatingMessageResponse }; + +export { SubmitTaskResponseSchema as SubmitOperatingMessageResponseSchema }; + +export { InterruptTaskRequest as InterruptOperatingThreadRequest }; + +export { InterruptTaskRequestSchema as InterruptOperatingThreadRequestSchema }; + +export { InterruptTaskResponse as InterruptOperatingThreadResponse }; + +export { InterruptTaskResponseSchema as InterruptOperatingThreadResponseSchema }; + +export { RespondToRequestRequest as RespondOperatingThreadRequest }; + +export { RespondToRequestRequestSchema as RespondOperatingThreadRequestSchema }; + +export { RespondToRequestResponse as RespondOperatingThreadResponse }; + +export { RespondToRequestResponseSchema as RespondOperatingThreadResponseSchema }; + +export { GetReceiptRequest as GetOperatingReceiptRequest }; + +export { GetReceiptRequestSchema as GetOperatingReceiptRequestSchema }; + +export { GetReceiptResponse as GetOperatingReceiptResponse }; + +export { GetReceiptResponseSchema as GetOperatingReceiptResponseSchema }; + +export { ResolveReceiptActionRequest as ResolveOperatingReceiptActionRequest }; + +export { ResolveReceiptActionRequestSchema as ResolveOperatingReceiptActionRequestSchema }; + +export { ResolveReceiptActionResponse as ResolveOperatingReceiptActionResponse }; + +export { ResolveReceiptActionResponseSchema as ResolveOperatingReceiptActionResponseSchema }; + +export { CodingContract as CodingAcceptanceContract }; + +export { CodingContractSchema as CodingAcceptanceContractSchema }; + +export { TaskTurn as OperatingThreadTurn }; + +export { TaskTurnSchema as OperatingThreadTurnSchema }; + +export { TaskEvent as OperatingThreadEvent }; + +export { TaskEventSchema as OperatingThreadEventSchema }; + +export { TaskMessage as OperatingMessage }; + +export { TaskMessageSchema as OperatingMessageSchema }; + +export { ReceiptAction as OperatingReceiptAction }; + +export { ReceiptActionSchema as OperatingReceiptActionSchema }; + +export { Receipt as OperatingReceipt }; + +export { ReceiptSchema as OperatingReceiptSchema }; + +export { Thread as OperatingChannel }; + +export { ThreadSchema as OperatingChannelSchema }; + +export { ModelSelection as OperatingModelSelection }; + +export { ModelSelectionSchema as OperatingModelSelectionSchema }; + +export { AvailableModel as InferenceProviderTarget }; + +export { AvailableModelSchema as InferenceProviderTargetSchema }; + +export { Thread as OperatingThreadExecution }; + +export { ThreadSchema as OperatingThreadExecutionSchema }; + +export { RespondToRequestRequest as OperatingThreadResponse }; + +export { RespondToRequestRequestSchema as OperatingThreadResponseSchema }; + +export { SetupReadiness as OperatingCapabilityState }; + +export { SetupReadinessSchema as OperatingCapabilityStateSchema }; + +export { TurnState as OperatingTurnState }; + +export { WaitingReason as OperatingThreadWaitingReason }; + +export { RequestKind as OperatingThreadRequestType }; + +export { ResponseAction as OperatingThreadResponseAction }; + +export { ReceiptState as ReceiptLifecycleState }; + +export { EventKind as OperatingThreadEventKind }; diff --git a/sdk/deixic/typescript/src/tasks.ts b/sdk/deixic/typescript/src/tasks.ts index 385dcfd..71f3d37 100644 --- a/sdk/deixic/typescript/src/tasks.ts +++ b/sdk/deixic/typescript/src/tasks.ts @@ -3,6 +3,7 @@ import { toBinary, } from "@bufbuild/protobuf"; import { + MessageRole, OperatingCapabilityStateSchema, OperatingModelSelectionSchema, InferenceProviderTargetSchema, @@ -21,9 +22,9 @@ import { type OperatingThreadEvent, type OperatingThreadTurn, type ListOperatingThreadEventsResponse, -} from "../../../../gen/ts/console/v1/console_pb.js"; -import type { MaestroProductClient } from "../../../maestro/typescript/src/client.js"; -import { MaestroProductError } from "../../../maestro/typescript/src/errors.js"; +} from "./protocol.js"; +import type { PublicClient } from "./client.js"; +import { PublicError } from "./errors.js"; const MAX_CURSOR = 9_223_372_036_854_775_807n; @@ -68,7 +69,7 @@ export type TaskResult = }) | (TaskResultBase & { status: "prepared" | "unacknowledged" | "responded" | "failed" | "interrupted" }) | (TaskResultBase & { status: "waiting"; reason?: string }) - | (TaskResultBase & { status: "unfinished"; reason?: string; error?: MaestroProductError }); + | (TaskResultBase & { status: "unfinished"; reason?: string; error?: PublicError }); export interface WaitTaskOptions { /** Observation budget in milliseconds. Expiry never interrupts remote work. */ @@ -86,7 +87,7 @@ export interface SetupCheck { channelId: string; capabilities: OperatingCapabilityState[]; nextAction: string; - error?: MaestroProductError; + error?: PublicError; modelSelection?: OperatingModelSelection; defaultModel?: InferenceProviderTarget; selectedModel?: InferenceProviderTarget; @@ -94,7 +95,7 @@ export interface SetupCheck { } export class TasksClient { - constructor(private readonly client: MaestroProductClient, private readonly baseUrl: string) {} + constructor(private readonly client: PublicClient, private readonly baseUrl: string) {} async prepare(input: PrepareTaskInput): Promise { const task = new Task(this.client, { @@ -142,29 +143,28 @@ export class TasksClient { const channelId = identity(input.channelId, "channelId"); try { const thread = await this.client.threads.get({ channelId, limit: 1, signal: input.signal }); - if (thread.channel?.id !== channelId) throw protocol("Setup lookup omitted or changed the channel identity"); - const capabilities = thread.capabilities.map(item => clone(OperatingCapabilityStateSchema, item)); - if (thread.channel.capabilityState) capabilities.push(clone(OperatingCapabilityStateSchema, thread.channel.capabilityState)); - const missing = capabilities.some(item => item.missingRequirements.length || item.missingRequirementStates.length); - const selection = thread.modelSelection; + if (thread.thread?.id !== channelId) throw protocol("Setup lookup omitted or changed the channel identity"); + const capabilities = thread.setup ? [clone(OperatingCapabilityStateSchema, thread.setup)] : []; + const missing = !thread.setup?.accessible || capabilities.some(item => item.missingRequirements.length); + const selection = thread.setup?.selection; const selected = selection && (selection.provider || selection.model) - ? thread.availableModels.find(item => item.provider === selection.provider && item.model === selection.model) - : thread.defaultModel; - // Platform deliberately omits both the catalog and default target when - // managed inference is unavailable. An explicit selection that no longer + ? thread.setup?.availableModels.find(item => item.provider === selection.provider && item.model === selection.model) + : thread.setup?.defaultModel; + // Platform omits both the catalog and default target when + // model access is unavailable. An explicit selection that no longer // appears in the catalog is unavailable for the same reason. const unavailableModel = selected === undefined || !selected.ready; return { status: missing || unavailableModel ? "needs_attention" : "accessible", channelId, capabilities, writeAccess: "not_checked", nextAction: missing ? "Resolve the reported workspace prerequisites" : unavailableModel ? "Check the reported model availability in workspace settings" : "Submit a task to check execution and write access", - ...(thread.modelSelection ? { modelSelection: clone(OperatingModelSelectionSchema, thread.modelSelection) } : {}), - ...(thread.defaultModel ? { defaultModel: clone(InferenceProviderTargetSchema, thread.defaultModel) } : {}), + ...(thread.setup?.selection ? { modelSelection: clone(OperatingModelSelectionSchema, thread.setup?.selection) } : {}), + ...(thread.setup?.defaultModel ? { defaultModel: clone(InferenceProviderTargetSchema, thread.setup?.defaultModel) } : {}), ...(selected ? { selectedModel: clone(InferenceProviderTargetSchema, selected) } : {}), }; } catch (error) { - if (!(error instanceof MaestroProductError)) throw error; - const actions: Partial> = { + if (!(error instanceof PublicError)) throw error; + const actions: Partial> = { authentication: "Replace or refresh the expired or invalid credential", authorization: "Check the credential's organization and workspace read grants", not_found: "Check the channel ID in this workspace", @@ -182,7 +182,7 @@ export class Task { private observing = false; private readonly state: TaskCheckpoint; - constructor(private readonly client: MaestroProductClient, state: TaskCheckpoint, + constructor(private readonly client: PublicClient, state: TaskCheckpoint, private readonly onCheckpoint?: PrepareTaskInput["onCheckpoint"]) { if (onCheckpoint !== undefined && typeof onCheckpoint !== "function") throw validation("onCheckpoint must be callable"); this.state = { ...state }; @@ -235,7 +235,7 @@ export class Task { for (let index = 0; index < maxPages; index += 1) { const page = await this.client.threads.get({ channelId: this.state.channelId, limit: 200, pageToken, signal: options.signal }); - if (page.channel?.id && page.channel.id !== this.state.channelId) throw protocol("Thread lookup changed the channel identity"); + if (page.thread?.id !== this.state.channelId) throw protocol("Thread lookup changed the channel identity"); const candidate = page.turns.find(item => item.turnId === turnId); if (candidate) { if (candidate.sequence !== sequence) throw protocol("Thread lookup changed the accepted turn sequence"); @@ -267,7 +267,7 @@ export class Task { default: return { ...base, status: "unfinished" }; } const message = messages.get(turn.assistantMessageId); - if (!message || message.role !== "assistant" || message.channelId !== this.state.channelId) { + if (!message || message.role !== MessageRole.ASSISTANT) { throw protocol("Completed turn omitted its linked final assistant message"); } const receipts: OperatingReceipt[] = []; @@ -302,7 +302,7 @@ export class Task { [OperatingThreadWaitingReason.EXTERNAL_RETRY]: OperatingThreadRequestType.EXTERNAL_RETRY, }; const expected = types[turn.waitingReason]; - return request?.requestType === expected ? request : undefined; + return request?.requestKind === expected ? request : undefined; } } return undefined; @@ -313,11 +313,11 @@ export class Task { const cursor = BigInt(this.state.cursor); const page = await this.client.events.list({ channelId: this.state.channelId, afterCursor: cursor, signal }); if (page.resetRequired) { - if (!page.threadExecution || page.threadExecution.replayCursor < cursor) { + if (!page.snapshot || page.snapshot.replayCursor < cursor) { throw protocol("Retention reset omitted a valid owner execution cursor"); } this.event = undefined; - this.state.cursor = page.threadExecution.replayCursor.toString(); + this.state.cursor = page.snapshot.replayCursor.toString(); await applicationCall(() => this.saveCheckpoint()); return true; } @@ -365,7 +365,7 @@ export class Task { } catch (error) { if (error instanceof ApplicationCallbackError) throw error.original; if (controller.signal.aborted) break; - if (!(error instanceof MaestroProductError) || !["transport", "unavailable"].includes(error.kind)) throw error; + if (!(error instanceof PublicError) || !["transport", "unavailable"].includes(error.kind)) throw error; if (reconnects >= maxReconnects) return { status: "unfinished", turnId: this.state.turnId, reason: "observation_error", error }; reconnects += 1; } @@ -429,8 +429,8 @@ function positive(value: number, name: string): number { if (!Number.isFinite(value) || value <= 0 || value > 2_147_483_647) throw validation(`${name} must be positive, finite, and within the supported timer range`); return value; } -function validation(message: string): MaestroProductError { return new MaestroProductError({ message, kind: "validation", status: 400 }); } -function protocol(message: string): MaestroProductError { return new MaestroProductError({ message, kind: "protocol" }); } +function validation(message: string): PublicError { return new PublicError({ message, kind: "validation", status: 400 }); } +function protocol(message: string): PublicError { return new PublicError({ message, kind: "protocol" }); } /** Apply an application's schema/parser to a completed answer; parser failures propagate. */ export function parseTaskResult(result: TaskResult, parser: (body: string) => T): T { diff --git a/sdk/deixic/typescript/test/account-brief.test.mjs b/sdk/deixic/typescript/test/account-brief.test.mjs index a7a76db..4f3313b 100644 --- a/sdk/deixic/typescript/test/account-brief.test.mjs +++ b/sdk/deixic/typescript/test/account-brief.test.mjs @@ -7,7 +7,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; import { create, fromBinary, toBinary } from "@bufbuild/protobuf"; -import * as pb from "../dist/gen/ts/console/v1/console_pb.js"; +import * as pb from "../dist/sdk/deixic/typescript/src/protocol.js"; const C = 9_007_199_254_740_994n; const script = fileURLToPath(import.meta.resolve("@evalops/deixic-sdk/examples/account-brief")); @@ -29,42 +29,42 @@ async function owner(loseAcceptance) { for await (const chunk of request) chunks.push(chunk); const data = Buffer.concat(chunks); try { - assert(request.url.startsWith("/deixic.v1.DeixicService/")); + assert(request.url.startsWith("/deixicpublic.v1.DeixicPublicService/")); assert.equal(request.headers["content-type"], "application/proto"); assert.equal(request.headers["connect-protocol-version"], "1"); assert.equal(request.headers.authorization, "Bearer fixture-secret"); const input = fromBinary(pb[method + "RequestSchema"], data); - assert.equal(input.query.organizationId, "org-fixture"); - assert.equal(input.query.workspaceId, "ws-fixture"); - assert.equal(request.headers["x-organization-id"], input.query.organizationId); - assert.equal(request.headers["x-workspace-id"], input.query.workspaceId); - assert.equal(input.channelId, "company"); + assert.equal(input.scope.organizationId, "org-fixture"); + assert.equal(input.scope.workspaceId, "ws-fixture"); + assert.equal(request.headers["x-organization-id"], input.scope.organizationId); + assert.equal(request.headers["x-workspace-id"], input.scope.workspaceId); + assert.equal(input.threadId, "company"); let fields; switch (method) { - case "SubmitOperatingMessage": + case "SubmitTask": submissions.push(data); assert.equal(input.idempotencyKey, "crm-event-001"); assert(input.body.includes("Example account")); if (operations.has(input.idempotencyKey)) assert.deepEqual(data, operations.get(input.idempotencyKey)); operations.set(input.idempotencyKey, data); if (loseAcceptance && submissions.length === 1) { request.socket.destroy(); return; } - fields = { replayCursor: C, acceptedTurn: { turnId: "target", sequence: 2n, state: pb.OperatingTurnState.QUEUED } }; + fields = { replayCursor: C, acceptedTurn: { turnId: "target", sequence: 2n, state: pb.OperatingTurnState.ACCEPTED } }; break; - case "ListOperatingThreadEvents": + case "ListEvents": completed = true; fields = { nextCursor: C + 1n, events: input.afterCursor < C + 1n ? [{ cursor: C + 1n, - turnId: "target", eventId: "completed", kind: pb.OperatingThreadEventKind.TURN_COMPLETED }] : [] }; + turnId: "target", id: "completed", kind: pb.OperatingThreadEventKind.TURN_COMPLETED }] : [] }; break; - case "GetOperatingThread": - fields = { channel: { id: "company" }, defaultModel: { provider: "fixture", model: "fixture", ready: true }, - turns: [{ turnId: "target", sequence: 2n, state: completed ? pb.OperatingTurnState.COMPLETED : pb.OperatingTurnState.QUEUED, + case "GetThread": + fields = { thread: { id: "company" }, setup: { accessible: true, defaultModel: { provider: "fixture", model: "fixture", ready: true } }, + turns: [{ turnId: "target", sequence: 2n, state: completed ? pb.OperatingTurnState.COMPLETED : pb.OperatingTurnState.ACCEPTED, assistantMessageId: completed ? "answer" : "" }], - messages: completed ? [{ id: "answer", channelId: "company", role: "assistant", + messages: completed ? [{ id: "answer", channelId: "company", role: 2, body: "Example account: an evidence-linked brief", receiptIds: ["evidence"] }] : [] }; break; - case "GetOperatingReceipt": + case "GetReceipt": assert.equal(input.receiptId, "evidence"); - fields = { receipt: { id: "evidence", lifecycleState: pb.ReceiptLifecycleState.VERIFIED } }; + fields = { receipt: { id: "evidence", state: pb.ReceiptLifecycleState.VERIFIED } }; break; default: throw new Error("unexpected mutation or RPC: " + method); } diff --git a/sdk/deixic/typescript/test/client.test.mjs b/sdk/deixic/typescript/test/client.test.mjs index 9947454..2d7bb12 100644 --- a/sdk/deixic/typescript/test/client.test.mjs +++ b/sdk/deixic/typescript/test/client.test.mjs @@ -3,12 +3,9 @@ import test from "node:test"; import { create } from "@bufbuild/protobuf"; import { - AssessComplianceSubjectResponseSchema, - GetComplianceAssessmentResponseSchema, - RecordComplianceAssessmentResponseSchema, - GetOperatingThreadResponseSchema, - SubmitOperatingMessageResponseSchema, -} from "../dist/gen/ts/console/v1/console_pb.js"; + GetThreadResponseSchema, + SubmitTaskResponseSchema, +} from "../dist/sdk/deixic/typescript/src/protocol.js"; import { DEFAULT_DEIXIC_BASE_URL, DeixicError, @@ -43,50 +40,19 @@ class RecordingTransport { } } -test("compliance assessments use the fixed tenant and a typed Deixic RPC", async () => { - const transport = new RecordingTransport(() => create(AssessComplianceSubjectResponseSchema, { - assessment: { profileId: "dex-production-action-assurance/v1", inspectedCount: 1, expectedCount: 1 }, - })); - const deixic = createDeixicClient({ - organizationId: "org-a", workspaceId: "workspace-a", apiKey: "sdk-test-key", transport, - }); - const response = await deixic.compliance.assess({ - profileId: "dex-production-action-assurance/v1", - subjectKind: "tool_execution", subjectId: "execution-1", - }); - assert.equal(response.assessment?.inspectedCount, 1); - assert.equal(transport.calls[0].method.name, "AssessComplianceSubject"); - assert.equal(transport.calls[0].method.parent.typeName, "deixic.v1.DeixicService"); - assert.equal(transport.calls[0].input.organizationId, "org-a"); - assert.equal(transport.calls[0].input.workspaceId, "workspace-a"); - assert.equal(transport.calls[0].input.subjectId, "execution-1"); -}); - -test("compliance records bind tenant and replay key through typed RPCs", async () => { - const transport = new RecordingTransport(({ method }) => create( - method.name === "RecordComplianceAssessment" - ? RecordComplianceAssessmentResponseSchema : GetComplianceAssessmentResponseSchema, - { record: { id: "ca_1" } }, - )); +test("public client exposes only supported task and thread facades", () => { + const transport = new RecordingTransport(() => { throw new Error("unexpected RPC"); }); const deixic = createDeixicClient({ organizationId: "org-a", workspaceId: "workspace-a", apiKey: "sdk-test-key", transport, }); - await deixic.compliance.record({ - profileId: "dex-production-action-assurance/v1", subjectKind: "tool_execution", - subjectId: "execution-1", idempotencyKey: "snapshot-1", - }); - await deixic.compliance.get({ recordId: "ca_1" }); - assert.deepEqual(transport.calls.map(({ method }) => method.name), [ - "RecordComplianceAssessment", "GetComplianceAssessment", + assert.deepEqual(Object.keys(deixic).sort(), [ + "controls", "events", "messages", "receipts", "scope", "tasks", "threads", ]); - assert.equal(transport.calls[0].input.organizationId, "org-a"); - assert.equal(transport.calls[0].input.workspaceId, "workspace-a"); - assert.equal(transport.calls[0].input.idempotencyKey, "snapshot-1"); - assert.equal(transport.calls[1].input.recordId, "ca_1"); + assert.equal("compliance" in deixic, false); }); test("public client fixes tenant scope and sends an API key as a bearer", async () => { - const transport = new RecordingTransport(() => create(SubmitOperatingMessageResponseSchema, { + const transport = new RecordingTransport(() => create(SubmitTaskResponseSchema, { replayCursor: 8n, acceptedTurn: { turnId: "turn-1", sequence: 2n }, })); @@ -111,13 +77,13 @@ test("public client fixes tenant scope and sends an API key as a bearer", async assert.equal(call.header.get("Authorization"), "Bearer sdk-test-key"); assert.equal(call.header.get("X-Organization-ID"), "org-a"); assert.equal(call.header.get("X-Workspace-ID"), "workspace-a"); - assert.equal(call.input.query.organizationId, "org-a"); - assert.equal(call.input.query.workspaceId, "workspace-a"); + assert.equal(call.input.scope.organizationId, "org-a"); + assert.equal(call.input.scope.workspaceId, "workspace-a"); assert.equal(call.input.idempotencyKey, "send-1"); }); test("public client rejects ambiguous credentials before transport", () => { - const transport = new RecordingTransport(() => create(GetOperatingThreadResponseSchema)); + const transport = new RecordingTransport(() => create(GetThreadResponseSchema)); assert.throws( () => createDeixicClient({ @@ -141,7 +107,7 @@ test("public client rejects an explicitly empty API key", () => { apiKey: " ", organizationId: "org-a", workspaceId: "workspace-a", - transport: new RecordingTransport(() => create(GetOperatingThreadResponseSchema)), + transport: new RecordingTransport(() => create(GetThreadResponseSchema)), }), (error) => error instanceof DeixicError && error.kind === "validation" @@ -150,7 +116,7 @@ test("public client rejects an explicitly empty API key", () => { }); test("public client rejects unsafe base URLs before transport", () => { - const transport = new RecordingTransport(() => create(GetOperatingThreadResponseSchema)); + const transport = new RecordingTransport(() => create(GetThreadResponseSchema)); for (const baseUrl of [ "deixic.example", "ftp://deixic.example", @@ -179,7 +145,7 @@ test("public client reports scope validation through DeixicError", () => { apiKey: "sdk-test-key", organizationId: " ", workspaceId: "workspace-a", - transport: new RecordingTransport(() => create(GetOperatingThreadResponseSchema)), + transport: new RecordingTransport(() => create(GetThreadResponseSchema)), }), (error) => error instanceof DeixicError && error.kind === "validation" @@ -195,3 +161,26 @@ test("native fetch rejection is unavailable; malformed responses remain protocol fetch: async () => new Response(new Uint8Array([255]), { headers: { "Content-Type": "application/proto" } }) }); await assert.rejects(malformed.threads.get({ channelId: "company" }), error => error.kind === "protocol"); }); + +test("request response cannot replace fixed scope or accepted turn coordinates", async () => { + const transport = new RecordingTransport(call => create(call.method.output)); + const sdk = createDeixicClient({ organizationId: "org-a", workspaceId: "workspace-a", apiKey: "fixture", transport }); + await sdk.controls.respond({ channelId: "thread-a", turnId: "turn-a", idempotencyKey: "decision-a", + response: { scope: { organizationId: "other", workspaceId: "other" }, threadId: "other", turnId: "other", + requestId: "request-a", requestKind: 1, action: 1 } }); + const call = transport.calls[0]; + assert.equal(call.method.parent.typeName, "deixicpublic.v1.DeixicPublicService"); + assert.equal(call.method.name, "RespondToRequest"); + assert.equal(call.input.scope.organizationId, "org-a"); + assert.equal(call.input.scope.workspaceId, "workspace-a"); + assert.equal(call.input.threadId, "thread-a"); + assert.equal(call.input.turnId, "turn-a"); + assert.equal(call.input.requestId, "request-a"); +}); + +test("unsupported offset pagination fails before any request", async () => { + const transport = new RecordingTransport(() => { throw new Error("unexpected request"); }); + const sdk = createDeixicClient({ organizationId: "org-a", workspaceId: "workspace-a", transport }); + await assert.rejects(async () => sdk.threads.get({ channelId: "thread-a", offset: 1 }), DeixicError); + assert.equal(transport.calls.length, 0); +}); diff --git a/sdk/deixic/typescript/test/tasks.test.mjs b/sdk/deixic/typescript/test/tasks.test.mjs index 8a777bc..16c74eb 100644 --- a/sdk/deixic/typescript/test/tasks.test.mjs +++ b/sdk/deixic/typescript/test/tasks.test.mjs @@ -3,23 +3,23 @@ import test from "node:test"; import { create } from "@bufbuild/protobuf"; import { Code, ConnectError } from "@connectrpc/connect"; import { - GetOperatingThreadResponseSchema, GetOperatingReceiptResponseSchema, - SubmitOperatingMessageResponseSchema, ListOperatingThreadEventsResponseSchema, + GetThreadResponseSchema, GetReceiptResponseSchema, + SubmitTaskResponseSchema, ListEventsResponseSchema, OperatingTurnState, OperatingThreadEventKind, OperatingThreadRequestType, OperatingThreadWaitingReason, -} from "../dist/gen/ts/console/v1/console_pb.js"; +} from "../dist/sdk/deixic/typescript/src/protocol.js"; import { createDeixicClient, DeixicError, parseTaskResult } from "../dist/sdk/deixic/typescript/src/index.js"; const C = 9_007_199_254_740_994n; -const acceptance = () => create(SubmitOperatingMessageResponseSchema, { - replayCursor: C, acceptedTurn: { turnId: "target", sequence: 2n, state: OperatingTurnState.QUEUED }, +const acceptance = () => create(SubmitTaskResponseSchema, { + replayCursor: C, acceptedTurn: { turnId: "target", sequence: 2n, state: OperatingTurnState.ACCEPTED }, }); -const finished = (options = {}) => create(GetOperatingThreadResponseSchema, { - channel: { id: "company" }, +const finished = (options = {}) => create(GetThreadResponseSchema, { + thread: { id: "company" }, turns: [{ turnId: "target", sequence: 2n, state: OperatingTurnState.COMPLETED, assistantMessageId: "answer", ...options.turn }], - messages: [{ id: "answer", channelId: "company", role: "assistant", body: "Account brief", ...options.message }], + messages: [{ id: "answer", channelId: "company", role: 2, body: "Account brief", ...options.message }], }); -const page = (options = {}) => create(ListOperatingThreadEventsResponseSchema, { nextCursor: C, ...options }); +const page = (options = {}) => create(ListEventsResponseSchema, { nextCursor: C, ...options }); class Transport { calls = []; @@ -68,7 +68,7 @@ test("completed result fetches exact linked answer and receipts across pages", a const second = finished({ message: { receiptIds: ["evidence"] } }); second.turns = []; const transport = new Transport([acceptance(), first, second, - create(GetOperatingReceiptResponseSchema, { receipt: { id: "evidence" } })]); + create(GetReceiptResponseSchema, { receipt: { id: "evidence" } })]); const result = await (await prepare(client(transport))).submit().then(task => task.result()); assert.equal(result.status, "completed"); assert.equal(result.body, "Account brief"); @@ -93,7 +93,7 @@ test("resume rejects tenant/origin changes and unsafe checkpoint coordinates", a test("retention reset uses owner execution cursor and ignores reset events", async () => { const transport = new Transport([acceptance(), page({ resetRequired: true, nextCursor: C + 9n, - threadExecution: { replayCursor: C + 2n }, + snapshot: { replayCursor: C + 2n }, events: [{ cursor: C + 9n, turnId: "target", kind: OperatingThreadEventKind.TURN_COMPLETED }], }), finished()]); const task = await (await prepare(client(transport))).submit(); @@ -108,19 +108,19 @@ test("reconnection retries observation without resubmission", async () => { const task = await (await prepare(client(transport))).submit(); assert.equal((await task.wait({ pollIntervalMs: 1 })).status, "completed"); assert.deepEqual(transport.calls.map(item => item.method), [ - "SubmitOperatingMessage", "ListOperatingThreadEvents", "ListOperatingThreadEvents", "GetOperatingThread", + "SubmitTask", "ListEvents", "ListEvents", "GetThread", ]); }); test("progress includes only new matching events and detaches callback data", async () => { - const own = { cursor: C + 2n, turnId: "target", eventId: "own", kind: OperatingThreadEventKind.PROGRESS }; + const own = { cursor: C + 2n, turnId: "target", id: "own", kind: OperatingThreadEventKind.PROGRESS }; const transport = new Transport([acceptance(), page({ nextCursor: C + 2n, events: [ { cursor: C + 1n, turnId: "other", kind: OperatingThreadEventKind.TURN_COMPLETED }, own, own, ] }), finished()]); const task = await (await prepare(client(transport))).submit(); const events = []; const result = await task.wait({ onEvent(event) { - events.push(event.eventId); + events.push(event.id); assert.throws(() => { event.turnId = "forged"; }, TypeError); } }); assert.deepEqual(events, ["own"]); @@ -133,8 +133,8 @@ test("pending approval request recovers from owner history after restart", async const saved = (await (await prepare(client(original))).submit()).checkpoint(); const transport = new Transport([ finished({ turn: { state: OperatingTurnState.WAITING, waitingReason: OperatingThreadWaitingReason.APPROVAL, firstCursor: C - 3n } }), - page({ nextCursor: C - 1n, events: [{ cursor: C - 1n, turnId: "target", eventId: "approval", - kind: OperatingThreadEventKind.APPROVAL_REQUIRED, requestId: "approval-1", requestType: OperatingThreadRequestType.APPROVAL }] }), + page({ nextCursor: C - 1n, events: [{ cursor: C - 1n, turnId: "target", id: "approval", + kind: OperatingThreadEventKind.APPROVAL_REQUIRED, requestId: "approval-1", requestKind: OperatingThreadRequestType.APPROVAL }] }), ]); const result = await client(transport).tasks.resume(saved).result(); assert.equal(result.status, "waiting"); @@ -159,10 +159,10 @@ for (const bad of ["sequence", "message_id", "role", "channel", "receipt"]) { if (bad === "sequence") result.turns[0].sequence = 3n; if (bad === "message_id") result.turns[0].assistantMessageId = "missing"; if (bad === "role") result.messages[0].role = "user"; - if (bad === "channel") result.messages[0].channelId = "other"; + if (bad === "channel") result.thread.id = "other"; if (bad === "receipt") { result.messages[0].receiptIds = ["requested"]; - tail.push(create(GetOperatingReceiptResponseSchema, { receipt: { id: "wrong" } })); + tail.push(create(GetReceiptResponseSchema, { receipt: { id: "wrong" } })); } const transport = new Transport([acceptance(), result, ...tail]); const task = await (await prepare(client(transport))).submit(); @@ -190,7 +190,7 @@ test("storage failure prevents submission; application errors are never retried" assert.equal(transport.calls.length, 0); const observing = new Transport([acceptance(), page({ nextCursor: C + 1n, - events: [{ cursor: C + 1n, turnId: "target", eventId: "own" }] })]); + events: [{ cursor: C + 1n, turnId: "target", id: "own" }] })]); const observed = await (await prepare(client(observing))).submit(); const failure = new DeixicError({ message: "application failure", kind: "transport" }); await assert.rejects(observed.wait({ onEvent() { throw failure; } }), error => error === failure); @@ -223,7 +223,7 @@ for (const [name, options] of [ ["skipped events", { nextCursor: C + 2n }], ["stalled pagination", { hasMore: true }], ["missing reset cursor", { resetRequired: true }], ["conflicting events", { nextCursor: C + 1n, events: [ - { cursor: C + 1n, turnId: "target", eventId: "a" }, { cursor: C + 1n, turnId: "target", eventId: "b" }, + { cursor: C + 1n, turnId: "target", id: "a" }, { cursor: C + 1n, turnId: "target", id: "b" }, ] }], ]) test(`invalid ${name} does not advance checkpoint`, async () => { const transport = new Transport([acceptance(), page(options)]); @@ -233,15 +233,13 @@ for (const [name, options] of [ }); test("setup preserves owner prerequisites and does not claim write access", async () => { - const transport = new Transport([create(GetOperatingThreadResponseSchema, { - channel: { id: "company" }, capabilities: [{ service: "crm", status: "unavailable", - missingRequirements: ["Connect CRM"], missingRequirementStates: [{ service: "crm", - reasonCode: "connection_missing", remediationRef: "settings/integrations" }] }], + const transport = new Transport([create(GetThreadResponseSchema, { + thread: { id: "company" }, setup: { accessible: false, missingRequirements: ["Connect CRM"] }, })]); const report = await client(transport).tasks.checkSetup({ channelId: "company" }); assert.equal(report.status, "needs_attention"); assert.equal(report.writeAccess, "not_checked"); - assert.equal(report.capabilities[0].missingRequirementStates[0].reasonCode, "connection_missing"); + assert.equal(report.capabilities[0].missingRequirements[0], "Connect CRM"); assert.equal(transport.calls.length, 1); }); @@ -255,13 +253,13 @@ test("setup failure has actionable grants guidance and support reference", async }); test("setup reports owner model availability", async () => { - const transport = new Transport([create(GetOperatingThreadResponseSchema, { - channel: { id: "company" }, defaultModel: { provider: "fixture", model: "chosen", - ready: false, unavailableReason: "grant_missing" }, + const transport = new Transport([create(GetThreadResponseSchema, { + thread: { id: "company" }, setup: { accessible: true, defaultModel: { provider: "fixture", model: "chosen", + ready: false } }, })]); const report = await client(transport).tasks.checkSetup({ channelId: "company" }); assert.equal(report.status, "needs_attention"); - assert.equal(report.defaultModel.unavailableReason, "grant_missing"); + assert.equal(report.defaultModel.ready, false); assert.equal(report.modelSelection, undefined); }); @@ -282,9 +280,9 @@ test("visible final answer does not scan unrelated old history", async () => { }); test("selected ready model is not blocked by unavailable default", async () => { - const transport = new Transport([create(GetOperatingThreadResponseSchema, { - channel: { id: "company" }, defaultModel: { provider: "fixture", model: "default", ready: false }, - modelSelection: { provider: "fixture", model: "chosen" }, availableModels: [{ provider: "fixture", model: "chosen", ready: true }], + const transport = new Transport([create(GetThreadResponseSchema, { + thread: { id: "company" }, setup: { accessible: true, defaultModel: { provider: "fixture", model: "default", ready: false }, + selection: { provider: "fixture", model: "chosen" }, availableModels: [{ provider: "fixture", model: "chosen", ready: true }] }, })]); const report = await client(transport).tasks.checkSetup({ channelId: "company" }); assert.equal(report.status, "accessible"); @@ -293,9 +291,9 @@ test("selected ready model is not blocked by unavailable default", async () => { }); for (const explicitSelection of [false, true]) test(`setup rejects an absent execution route (${explicitSelection ? "removed selection" : "no default"})`, async () => { - const transport = new Transport([create(GetOperatingThreadResponseSchema, { - channel: { id: "company" }, - ...(explicitSelection ? { modelSelection: { provider: "fixture", model: "removed" } } : {}), + const transport = new Transport([create(GetThreadResponseSchema, { + thread: { id: "company" }, + setup: { accessible: true, ...(explicitSelection ? { selection: { provider: "fixture", model: "removed" } } : {}) }, })]); const report = await client(transport).tasks.checkSetup({ channelId: "company" }); assert.equal(report.status, "needs_attention"); @@ -311,7 +309,7 @@ test("parser failures propagate without changing completion", async () => { }); test("invalid acceptance stays unacknowledged and requires explicit replay", async () => { - const transport = new Transport([create(SubmitOperatingMessageResponseSchema)]); + const transport = new Transport([create(SubmitTaskResponseSchema)]); const task = await prepare(client(transport)); await assert.rejects(task.submit(), error => error instanceof DeixicError && error.kind === "protocol"); assert.equal((await task.result()).status, "unacknowledged"); diff --git a/sdk/deixic/typescript/tsconfig.json b/sdk/deixic/typescript/tsconfig.json index 8293c4d..e2bc97b 100644 --- a/sdk/deixic/typescript/tsconfig.json +++ b/sdk/deixic/typescript/tsconfig.json @@ -14,8 +14,8 @@ "rootDir": "../../..", "strict": true, "declaration": true, - "declarationMap": true, - "sourceMap": true, + "declarationMap": false, + "sourceMap": false, "skipLibCheck": true, "esModuleInterop": true },