@vercel/factory 0.0.15 → 0.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +356 -0
- package/README.md +49 -261
- package/dist/agent-routes.d.mts +47 -3
- package/dist/agent-routes.mjs +28 -1
- package/dist/agent-routes.mjs.map +1 -1
- package/dist/api-contracts.d.mts +20 -1
- package/dist/api-contracts.mjs +2 -1
- package/dist/api-contracts.mjs.map +1 -1
- package/dist/api.d.mts +45 -2
- package/dist/api.mjs +199 -10
- package/dist/api.mjs.map +1 -1
- package/dist/approval-contracts.d.mts +6 -0
- package/dist/blob/index.d.mts +51 -14
- package/dist/blob/index.mjs +26 -10
- package/dist/blob/index.mjs.map +1 -1
- package/dist/budget.d.mts +7 -0
- package/dist/budget.mjs +6 -0
- package/dist/budget.mjs.map +1 -1
- package/dist/build-factory.d.mts +1 -0
- package/dist/change-verification/dispatch.d.mts +16 -3
- package/dist/change-verification/dispatch.mjs +45 -7
- package/dist/change-verification/dispatch.mjs.map +1 -1
- package/dist/change-verification/eve-tool.d.mts +2 -1
- package/dist/change-verification/eve-tool.mjs +35 -47
- package/dist/change-verification/eve-tool.mjs.map +1 -1
- package/dist/change-verification/result.mjs +130 -0
- package/dist/change-verification/result.mjs.map +1 -0
- package/dist/changes/eve-record-change.d.mts +2 -2
- package/dist/changes/eve-record-change.mjs +43 -9
- package/dist/changes/eve-record-change.mjs.map +1 -1
- package/dist/changes.d.mts +4 -3
- package/dist/changes.mjs +2 -2
- package/dist/changes.mjs.map +1 -1
- package/dist/client-events.d.mts +10 -3
- package/dist/client-events.mjs +6 -2
- package/dist/client-events.mjs.map +1 -1
- package/dist/client-stream.mjs +8 -2
- package/dist/client-stream.mjs.map +1 -1
- package/dist/client-transcript.mjs +5 -1
- package/dist/client-transcript.mjs.map +1 -1
- package/dist/client.d.mts +121 -12
- package/dist/client.mjs +117 -9
- package/dist/client.mjs.map +1 -1
- package/dist/code-review/contracts.d.mts +1 -0
- package/dist/code-review/eve-post-review.d.mts +4 -4
- package/dist/code-review/eve-post-review.mjs +29 -17
- package/dist/code-review/eve-post-review.mjs.map +1 -1
- package/dist/code-review/eve-review-comments.d.mts +13 -2
- package/dist/code-review/eve-review-comments.mjs +45 -11
- package/dist/code-review/eve-review-comments.mjs.map +1 -1
- package/dist/code-review/github-reporter.d.mts +2 -0
- package/dist/code-review/github-reporter.mjs +7 -5
- package/dist/code-review/github-reporter.mjs.map +1 -1
- package/dist/code-review.d.mts +3 -2
- package/dist/deepsec/eve-tool.mjs +3 -1
- package/dist/deepsec/eve-tool.mjs.map +1 -1
- package/dist/dispatch.d.mts +79 -8
- package/dist/dispatch.mjs +68 -9
- package/dist/dispatch.mjs.map +1 -1
- package/dist/eve/index.d.mts +70 -10
- package/dist/eve/index.mjs +93 -22
- package/dist/eve/index.mjs.map +1 -1
- package/dist/eve/invoke.mjs +24 -11
- package/dist/eve/invoke.mjs.map +1 -1
- package/dist/eve/session-client.d.mts +122 -4
- package/dist/eve/session-client.mjs +127 -13
- package/dist/eve/session-client.mjs.map +1 -1
- package/dist/eve/task-execution.d.mts +380 -0
- package/dist/eve/task-execution.mjs +57 -2
- package/dist/eve/task-execution.mjs.map +1 -1
- package/dist/eve/task-session.d.mts +44 -2
- package/dist/eve/task-session.mjs +44 -2
- package/dist/eve/task-session.mjs.map +1 -1
- package/dist/eve/transcript.mjs +5 -1
- package/dist/eve/transcript.mjs.map +1 -1
- package/dist/execution.d.mts +117 -9
- package/dist/execution.mjs +76 -6
- package/dist/execution.mjs.map +1 -1
- package/dist/finding-remediation/admission.d.mts +2 -0
- package/dist/finding-remediation/admission.mjs +4 -1
- package/dist/finding-remediation/admission.mjs.map +1 -1
- package/dist/findings.d.mts +1 -0
- package/dist/github-publication.d.mts +1 -0
- package/dist/github-publication.mjs +97 -84
- package/dist/github-publication.mjs.map +1 -1
- package/dist/github-transfer.d.mts +15 -6
- package/dist/github-transfer.mjs +214 -66
- package/dist/github-transfer.mjs.map +1 -1
- package/dist/github.d.mts +51 -11
- package/dist/github.mjs +126 -24
- package/dist/github.mjs.map +1 -1
- package/dist/inbox-activity.d.mts +53 -0
- package/dist/inbox-activity.mjs +41 -0
- package/dist/inbox-activity.mjs.map +1 -0
- package/dist/index.d.mts +3 -1
- package/dist/index.mjs +3 -2
- package/dist/intake-contracts.d.mts +0 -1
- package/dist/integrations/deepsec.d.mts +1 -0
- package/dist/integrations/github.d.mts +2 -2
- package/dist/integrations/github.mjs +2 -2
- package/dist/integrations/slack.d.mts +3 -1
- package/dist/integrations/slack.mjs +3 -1
- package/dist/integrations/vercel.d.mts +4 -2
- package/dist/integrations/vercel.mjs +3 -2
- package/dist/merge-resolution/eve-tools.d.mts +1 -0
- package/dist/merge-resolution/eve-tools.mjs +7 -2
- package/dist/merge-resolution/eve-tools.mjs.map +1 -1
- package/dist/model-settings.d.mts +41 -0
- package/dist/model-settings.mjs +35 -0
- package/dist/model-settings.mjs.map +1 -0
- package/dist/planning/reconcile.mjs +6 -0
- package/dist/planning/reconcile.mjs.map +1 -1
- package/dist/postgres/index.d.mts +43 -2
- package/dist/postgres/index.mjs +40 -2
- package/dist/postgres/index.mjs.map +1 -1
- package/dist/presets/software-development/dispatch.d.mts +4 -1
- package/dist/presets/software-development/dispatch.mjs +2 -1
- package/dist/presets/software-development/dispatch.mjs.map +1 -1
- package/dist/presets/software-development/task-communication.d.mts +1 -0
- package/dist/presets/software-development/task-communication.mjs +48 -11
- package/dist/presets/software-development/task-communication.mjs.map +1 -1
- package/dist/presets/software-development.d.mts +1 -0
- package/dist/pull-requests/github-publisher.d.mts +15 -1
- package/dist/pull-requests/github-publisher.mjs +61 -1
- package/dist/pull-requests/github-publisher.mjs.map +1 -1
- package/dist/pull-requests.d.mts +1 -0
- package/dist/sandbox/index.d.mts +1 -0
- package/dist/schema/agent-route.d.mts +19 -1
- package/dist/schema/agent-route.mjs +19 -1
- package/dist/schema/agent-route.mjs.map +1 -1
- package/dist/schema/factory-config.d.mts +27 -0
- package/dist/schema/factory-config.mjs +33 -3
- package/dist/schema/factory-config.mjs.map +1 -1
- package/dist/schema/repository.d.mts +4 -0
- package/dist/schema/repository.mjs +5 -1
- package/dist/schema/repository.mjs.map +1 -1
- package/dist/schema/session.d.mts +1 -0
- package/dist/schema/session.mjs +1 -0
- package/dist/schema/session.mjs.map +1 -1
- package/dist/schema/slack-pr-notifications.d.mts +12 -0
- package/dist/schema/slack-pr-notifications.mjs +11 -0
- package/dist/schema/slack-pr-notifications.mjs.map +1 -0
- package/dist/schema/task-graph.d.mts +39 -0
- package/dist/schema/task.d.mts +1 -0
- package/dist/schema/task.mjs +2 -1
- package/dist/schema/task.mjs.map +1 -1
- package/dist/schema/transcript.d.mts +6 -0
- package/dist/schema/transcript.mjs +2 -1
- package/dist/schema/transcript.mjs.map +1 -1
- package/dist/schema/work.d.mts +52 -3
- package/dist/schema/work.mjs.map +1 -1
- package/dist/session-previews.d.mts +76 -0
- package/dist/session-previews.mjs +55 -0
- package/dist/session-previews.mjs.map +1 -0
- package/dist/session-review.d.mts +120 -0
- package/dist/session-review.mjs +79 -0
- package/dist/session-review.mjs.map +1 -0
- package/dist/signal-triage.mjs +1 -1
- package/dist/signals.d.mts +1 -0
- package/dist/stall.d.mts +4 -1
- package/dist/stall.mjs +6 -2
- package/dist/stall.mjs.map +1 -1
- package/dist/store/driver.d.mts +1 -1
- package/dist/store/driver.mjs.map +1 -1
- package/dist/store/engine.d.mts +206 -8
- package/dist/store/engine.mjs +147 -13
- package/dist/store/engine.mjs.map +1 -1
- package/dist/store/memory.d.mts +18 -1
- package/dist/store/memory.mjs +18 -1
- package/dist/store/memory.mjs.map +1 -1
- package/dist/store/slack-pr-notifications.d.mts +44 -0
- package/dist/store/slack-pr-notifications.mjs +121 -0
- package/dist/store/slack-pr-notifications.mjs.map +1 -0
- package/dist/store/task-work.d.mts +121 -6
- package/dist/store/task-work.mjs +7 -4
- package/dist/store/task-work.mjs.map +1 -1
- package/dist/sweep.d.mts +28 -6
- package/dist/sweep.mjs +34 -6
- package/dist/sweep.mjs.map +1 -1
- package/dist/task-graph-view.d.mts +3 -0
- package/dist/tasks.d.mts +3 -3
- package/dist/tasks.mjs +3 -3
- package/dist/vercel-git.d.mts +35 -3
- package/dist/vercel-git.mjs +265 -33
- package/dist/vercel-git.mjs.map +1 -1
- package/dist/vercel-github-api.d.mts +103 -0
- package/dist/vercel-github-api.mjs +363 -0
- package/dist/vercel-github-api.mjs.map +1 -0
- package/dist/vercel.d.mts +3 -2
- package/dist/vercel.mjs +3 -2
- package/dist/vercel.mjs.map +1 -1
- package/dist/work-triage.d.mts +1 -0
- package/dist/workflows.d.mts +102 -4
- package/dist/workflows.mjs +55 -2
- package/dist/workflows.mjs.map +1 -1
- package/dist/workspace-files-git.d.mts +15 -0
- package/dist/workspace-files-git.mjs +61 -0
- package/dist/workspace-files-git.mjs.map +1 -0
- package/dist/workspace-files.d.mts +107 -0
- package/dist/workspace-files.mjs +74 -0
- package/dist/workspace-files.mjs.map +1 -0
- package/docs/getting-started.md +104 -0
- package/docs/index.md +100 -0
- package/docs/recipes/cancellation.md +215 -0
- package/docs/recipes/custom-workflow.md +153 -0
- package/docs/recipes/dependent-tasks.md +207 -0
- package/docs/recipes/eve-agent.md +277 -0
- package/docs/recipes/human-input.md +204 -0
- package/docs/recipes/persistence-recovery.md +268 -0
- package/docs/recipes/retry-recovery.md +241 -0
- package/docs/recipes/task-messaging.md +215 -0
- package/docs/recipes/typed-eve-result.md +161 -0
- package/docs/runtime-integration.md +137 -0
- package/package.json +17 -6
package/dist/api-contracts.mjs
CHANGED
|
@@ -19,6 +19,7 @@ const apiAgentSchema = z.strictObject({
|
|
|
19
19
|
const createSessionRequestSchema = z.strictObject({
|
|
20
20
|
operationId: z.string().trim().min(1).max(200).describe("Client-generated idempotency key; retain when retrying creation."),
|
|
21
21
|
agent: apiAgentSchema.shape.id,
|
|
22
|
+
model: z.string().trim().min(1).max(200).optional().describe("Explicit supported model; absent uses the repository or application default."),
|
|
22
23
|
repository: repositorySlugSchema.optional().describe("Configured owner/repo slug."),
|
|
23
24
|
changeId: changeIdSchema.optional().describe("Existing change to review, verify, or continue."),
|
|
24
25
|
message: agentSessionMessageSchema,
|
|
@@ -90,7 +91,7 @@ const sessionViewSchema = z.strictObject({
|
|
|
90
91
|
/** Validates a cursor-paginated page of operator-facing sessions. */
|
|
91
92
|
const sessionPageSchema = z.strictObject({
|
|
92
93
|
sessions: z.array(sessionViewSchema).readonly().describe("Sessions in this page."),
|
|
93
|
-
nextCursor:
|
|
94
|
+
nextCursor: z.string().min(1).nullable().default(null).describe("Opaque cursor to pass unchanged for the next page, or null after the final page."),
|
|
94
95
|
totalCount: z.number().int().nonnegative().optional().describe("Total matching sessions when explicitly requested.")
|
|
95
96
|
});
|
|
96
97
|
/** Validates one configured repository exposed by the operator API. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-contracts.mjs","names":[],"sources":["../src/api-contracts.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { hasMessageContent, imageAttachmentsSchema, type ImageAttachment } from \"./image-input\";\nimport {\n changeIdSchema,\n repositoryIdSchema,\n taskIdSchema,\n type ChangeId,\n type TaskId,\n} from \"./schema/id\";\nimport { repositorySlugSchema, type RepositorySlug } from \"./schema/repository\";\nimport {\n agentRouteBindingSchema,\n type AgentRouteBinding,\n type AgentRouteBindingInput,\n} from \"./schema/agent-route\";\nimport {\n agentSessionIdSchema,\n agentSessionMessageSchema,\n agentSessionSchema,\n} from \"./schema/session\";\nimport { taskSchema, executionReferenceSchema } from \"./schema/task\";\n\n/** Validates an agent exposed by the operator API. */\nexport const apiAgentSchema = z.strictObject({\n id: z\n .string()\n .regex(/^[a-z][a-z0-9-]{0,31}$/u)\n .describe(\"Agent name used for discovery, filtering, and session creation when allowed.\"),\n description: z.string().describe(\"What this agent does.\"),\n route: agentRouteBindingSchema\n .optional()\n .describe(\"Exact registered specialist route; absent for conversations.\"),\n canStart: z\n .boolean()\n .describe(\"Whether an operator may start this agent directly through the session API.\"),\n requiresRepository: z.boolean().describe(\"Whether creation requires a configured repository.\"),\n requiresChange: z.boolean().describe(\"Whether creation requires an existing change ID.\"),\n});\n/** An agent exposed for operator discovery, filtering, or session creation. */\nexport type ApiAgent = Readonly<\n Omit<z.infer<typeof apiAgentSchema>, \"route\"> & {\n readonly route?: AgentRouteBinding;\n }\n>;\n\n/** Caller input for exposing an agent through the operator API before validation and branding. */\nexport interface ApiAgentInput {\n readonly id: string;\n readonly description: string;\n readonly route?: AgentRouteBindingInput;\n readonly canStart: boolean;\n readonly requiresRepository: boolean;\n readonly requiresChange: boolean;\n}\n\n/** Validates an idempotent request to create an operator session. */\nexport const createSessionRequestSchema = z\n .strictObject({\n operationId: z\n .string()\n .trim()\n .min(1)\n .max(200)\n .describe(\"Client-generated idempotency key; retain when retrying creation.\"),\n agent: apiAgentSchema.shape.id,\n repository: repositorySlugSchema.optional().describe(\"Configured owner/repo slug.\"),\n changeId: changeIdSchema.optional().describe(\"Existing change to review, verify, or continue.\"),\n message: agentSessionMessageSchema,\n attachments: imageAttachmentsSchema\n .optional()\n .describe(\"Uploaded images accompanying this message.\"),\n })\n .refine(hasMessageContent, \"Enter a message or attach an image\");\n/** An idempotent request to create an operator session. */\nexport type CreateSessionRequest = Readonly<\n Omit<z.input<typeof createSessionRequestSchema>, \"attachments\" | \"repository\" | \"changeId\">\n> & {\n readonly repository?: RepositorySlug;\n readonly changeId?: ChangeId;\n readonly attachments?: readonly ImageAttachment[];\n};\n\n/** Validates a message sent to an existing session with optimistic execution matching. */\nexport const sendSessionMessageRequestSchema = z\n .strictObject({\n message: agentSessionMessageSchema,\n attachments: imageAttachmentsSchema\n .optional()\n .describe(\"Uploaded images accompanying this message.\"),\n operationId: z\n .string()\n .trim()\n .min(1)\n .max(200)\n .optional()\n .describe(\"Required for a follow-up after completion; retain unchanged for retries.\"),\n turnPolicy: z\n .enum([\"steer\", \"queue\"])\n .default(\"steer\")\n .describe(\"Whether an active turn is steered immediately or the message is queued.\"),\n executionId: z\n .string()\n .min(1)\n .nullable()\n .describe(\"Observed execution ID; stale writes are rejected.\"),\n })\n .refine(hasMessageContent, \"Enter a message or attach an image\");\n\n/** Message sent to an existing session with optimistic execution matching. */\nexport type SendSessionMessageRequest = Readonly<\n Omit<z.input<typeof sendSessionMessageRequestSchema>, \"attachments\">\n> & {\n readonly attachments?: readonly ImageAttachment[];\n};\n\nconst sessionInputResponseBase = {\n requestId: z.string().min(1).describe(\"Pending provider input request ID.\"),\n};\n\n/** Validates an option selection or freeform answer to one provider input request. */\nexport const sessionInputResponseSchema = z.union([\n z.strictObject({\n ...sessionInputResponseBase,\n optionId: z.string().min(1).describe(\"Selected option ID.\"),\n text: z.never().optional().describe(\"Absent for an option selection.\"),\n }),\n z.strictObject({\n ...sessionInputResponseBase,\n optionId: z.never().optional().describe(\"Absent for a freeform answer.\"),\n text: z.string().min(1).describe(\"Freeform answer text.\"),\n }),\n]);\n/** A response to one pending provider input request. */\nexport type SessionInputResponse = Readonly<z.input<typeof sessionInputResponseSchema>>;\n\n/** Validates responses submitted to pending provider input requests. */\nexport const submitSessionInputRequestSchema = z.strictObject({\n executionId: z\n .string()\n .min(1)\n .describe(\"Observed provider session ID; stale input responses are rejected.\"),\n inputResponses: z\n .array(sessionInputResponseSchema)\n .min(1)\n .readonly()\n .describe(\"Responses to pending human-input requests.\"),\n});\n/** Responses submitted to pending provider input requests. */\nexport interface SubmitSessionInputRequest {\n readonly executionId: string;\n readonly inputResponses: readonly SessionInputResponse[];\n}\n\n/** Validates an execution-aware session control request. */\nexport const controlSessionRequestSchema = z.strictObject({\n executionId: z\n .string()\n .min(1)\n .optional()\n .describe(\"Observed provider session ID; guards against a replaced execution.\"),\n turnId: z.string().min(1).optional().describe(\"Observed turn ID for cooperative interruption.\"),\n});\n/** Execution and turn observed before requesting a session control operation. */\nexport type ControlSessionRequest = Readonly<z.input<typeof controlSessionRequestSchema>>;\n\n/** Validates an authenticated answer to a workflow question. */\nexport const answerSessionQuestionRequestSchema = z.strictObject({\n questionId: taskIdSchema.describe(\"Question Task belonging to this operator session.\"),\n answer: z.string().min(1).max(16000).describe(\"Authenticated immutable human answer.\"),\n});\n/** Authenticated answer to a workflow question in a session. */\nexport interface AnswerSessionQuestionRequest {\n readonly questionId: TaskId;\n readonly answer: string;\n}\n\n/** Validates the current operator-facing projection of a Factory session. */\nexport const sessionViewSchema = z.strictObject({\n session: agentSessionSchema.describe(\"Durable interaction binding.\"),\n task: taskSchema.nullable().describe(\"Current task state, if workflow-backed.\"),\n dependencyTaskIds: z\n .array(taskIdSchema)\n .readonly()\n .optional()\n .describe(\"Read-only current Task dependencies projected from its authoritative task graph.\"),\n execution: executionReferenceSchema\n .nullable()\n .describe(\"Current execution; may change after recovery.\"),\n activeAgent: z\n .string()\n .optional()\n .describe(\"Agent executing the selected work in this conversation.\"),\n source: z.string().optional().describe(\"Original trigger of automatically started work.\"),\n prUrl: z.string().optional().describe(\"Pull request associated with the conversation.\"),\n attention: z\n .enum([\"question\", \"failed\", \"stalled\", \"review\", \"conversation\"])\n .optional()\n .describe(\n \"Current human action: answer a question, inspect failed or stalled work, review a ready Change, or continue an external conversation.\",\n ),\n canFollowUp: z\n .boolean()\n .optional()\n .describe(\"Whether completed work can start a budgeted discussion in this conversation.\"),\n hasWorkflowFailure: z\n .boolean()\n .optional()\n .describe(\"Whether delegated workflow work has failed, independently of a pending question.\"),\n canCancel: z\n .boolean()\n .optional()\n .describe(\n \"Whether cancellation is available for the conversation or its delegated workflow work.\",\n ),\n history: z\n .array(\n z.strictObject({\n taskId: taskIdSchema.optional().describe(\"Task owning this execution, if any.\"),\n agent: z.string().describe(\"Agent that owns the provider execution.\"),\n message: z.string().describe(\"Initial request displayed for this execution.\"),\n attachments: imageAttachmentsSchema\n .optional()\n .describe(\"Images accompanying this execution's initial user request.\"),\n execution: executionReferenceSchema.describe(\"Authorized provider execution to replay.\"),\n }),\n )\n .readonly()\n .optional()\n .describe(\"Earlier executions, in conversation order, including replacement attempts.\"),\n relatedTasks: z\n .array(taskSchema)\n .readonly()\n .optional()\n .describe(\"Work linked to this conversation, including specialist delegations.\"),\n question: taskSchema\n .nullable()\n .describe(\"Open Factory question requiring an authenticated answer.\"),\n});\n/** The current operator-facing projection of a Factory session. */\nexport type SessionView = z.infer<typeof sessionViewSchema>;\n\n/** Validates a cursor-paginated page of operator-facing sessions. */\nexport const sessionPageSchema = z.strictObject({\n sessions: z.array(sessionViewSchema).readonly().describe(\"Sessions in this page.\"),\n nextCursor: agentSessionIdSchema\n .nullable()\n .default(null)\n .describe(\"Session ID that starts the next page, or null after the final page.\"),\n totalCount: z\n .number()\n .int()\n .nonnegative()\n .optional()\n .describe(\"Total matching sessions when explicitly requested.\"),\n});\n/** Cursor-paginated operator-facing sessions. */\nexport type SessionPage = z.infer<typeof sessionPageSchema>;\n\n/** Validates one configured repository exposed by the operator API. */\nexport const repositorySummarySchema = z.strictObject({\n id: repositoryIdSchema.describe(\"Stable configured repository identifier.\"),\n slug: repositorySlugSchema.describe(\"Configured owner/repository slug.\"),\n});\n/** Configured repository exposed by the operator API. */\nexport type RepositorySummary = z.infer<typeof repositorySummarySchema>;\n\n/** Validates repository slugs and their stable identifiers. */\nexport const repositoryDetailsSchema = z.strictObject({\n repositories: z\n .array(repositorySlugSchema)\n .readonly()\n .describe(\"Configured owner/repository slugs.\"),\n details: z\n .array(repositorySummarySchema)\n .readonly()\n .default([])\n .describe(\"Stable identifiers and slugs for configured repositories.\"),\n});\n/** Repository slugs and their stable configured identifiers. */\nexport type RepositoryDetails = z.infer<typeof repositoryDetailsSchema>;\n\n/** Validates a locally retained follow-up awaiting confirmed API acceptance. */\nexport const pendingFollowUpSchema = z\n .strictObject({\n sessionId: agentSessionIdSchema.describe(\"Conversation containing this follow-up.\"),\n operationId: z\n .string()\n .min(1)\n .max(200)\n .describe(\"Stable operation id retained until acceptance is confirmed.\"),\n executionId: z\n .string()\n .nullable()\n .describe(\"Execution observed before sending, or null before execution starts.\"),\n message: agentSessionMessageSchema,\n attachments: imageAttachmentsSchema\n .optional()\n .describe(\"Uploaded images accompanying this message.\"),\n turnPolicy: z.enum([\"steer\", \"queue\"]).describe(\"Requested turn policy.\"),\n })\n .refine(hasMessageContent, \"Enter a message or attach an image\");\n/** A locally retained follow-up awaiting confirmed API acceptance. */\nexport type PendingFollowUp = Readonly<\n Omit<z.output<typeof pendingFollowUpSchema>, \"attachments\">\n> & {\n readonly attachments?: readonly ImageAttachment[];\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api-contracts.mjs","names":[],"sources":["../src/api-contracts.ts"],"sourcesContent":["import { z } from \"zod\";\nimport { hasMessageContent, imageAttachmentsSchema, type ImageAttachment } from \"./image-input\";\nimport {\n changeIdSchema,\n repositoryIdSchema,\n taskIdSchema,\n type ChangeId,\n type TaskId,\n} from \"./schema/id\";\nimport { repositorySlugSchema, type RepositorySlug } from \"./schema/repository\";\nimport {\n agentRouteBindingSchema,\n type AgentRouteBinding,\n type AgentRouteBindingInput,\n} from \"./schema/agent-route\";\nimport {\n agentSessionIdSchema,\n agentSessionMessageSchema,\n agentSessionSchema,\n} from \"./schema/session\";\nimport { taskSchema, executionReferenceSchema } from \"./schema/task\";\n\n/** Validates an agent exposed by the operator API. */\nexport const apiAgentSchema = z.strictObject({\n id: z\n .string()\n .regex(/^[a-z][a-z0-9-]{0,31}$/u)\n .describe(\"Agent name used for discovery, filtering, and session creation when allowed.\"),\n description: z.string().describe(\"What this agent does.\"),\n route: agentRouteBindingSchema\n .optional()\n .describe(\"Exact registered specialist route; absent for conversations.\"),\n canStart: z\n .boolean()\n .describe(\"Whether an operator may start this agent directly through the session API.\"),\n requiresRepository: z.boolean().describe(\"Whether creation requires a configured repository.\"),\n requiresChange: z.boolean().describe(\"Whether creation requires an existing change ID.\"),\n});\n/** An agent exposed for operator discovery, filtering, or session creation. */\nexport type ApiAgent = Readonly<\n Omit<z.infer<typeof apiAgentSchema>, \"route\"> & {\n readonly route?: AgentRouteBinding;\n }\n>;\n\n/** Caller input for exposing an agent through the operator API before validation and branding. */\nexport interface ApiAgentInput {\n readonly id: string;\n readonly description: string;\n readonly route?: AgentRouteBindingInput;\n readonly canStart: boolean;\n readonly requiresRepository: boolean;\n readonly requiresChange: boolean;\n}\n\n/** Validates an idempotent request to create an operator session. */\nexport const createSessionRequestSchema = z\n .strictObject({\n operationId: z\n .string()\n .trim()\n .min(1)\n .max(200)\n .describe(\"Client-generated idempotency key; retain when retrying creation.\"),\n agent: apiAgentSchema.shape.id,\n model: z\n .string()\n .trim()\n .min(1)\n .max(200)\n .optional()\n .describe(\"Explicit supported model; absent uses the repository or application default.\"),\n repository: repositorySlugSchema.optional().describe(\"Configured owner/repo slug.\"),\n changeId: changeIdSchema.optional().describe(\"Existing change to review, verify, or continue.\"),\n message: agentSessionMessageSchema,\n attachments: imageAttachmentsSchema\n .optional()\n .describe(\"Uploaded images accompanying this message.\"),\n })\n .refine(hasMessageContent, \"Enter a message or attach an image\");\n/** An idempotent request to create an operator session. */\nexport type CreateSessionRequest = Readonly<\n Omit<z.input<typeof createSessionRequestSchema>, \"attachments\" | \"repository\" | \"changeId\">\n> & {\n readonly repository?: RepositorySlug;\n readonly changeId?: ChangeId;\n readonly attachments?: readonly ImageAttachment[];\n};\n\n/** Validates a message sent to an existing session with optimistic execution matching. */\nexport const sendSessionMessageRequestSchema = z\n .strictObject({\n message: agentSessionMessageSchema,\n attachments: imageAttachmentsSchema\n .optional()\n .describe(\"Uploaded images accompanying this message.\"),\n operationId: z\n .string()\n .trim()\n .min(1)\n .max(200)\n .optional()\n .describe(\"Required for a follow-up after completion; retain unchanged for retries.\"),\n turnPolicy: z\n .enum([\"steer\", \"queue\"])\n .default(\"steer\")\n .describe(\"Whether an active turn is steered immediately or the message is queued.\"),\n executionId: z\n .string()\n .min(1)\n .nullable()\n .describe(\"Observed execution ID; stale writes are rejected.\"),\n })\n .refine(hasMessageContent, \"Enter a message or attach an image\");\n\n/** Message sent to an existing session with optimistic execution matching. */\nexport type SendSessionMessageRequest = Readonly<\n Omit<z.input<typeof sendSessionMessageRequestSchema>, \"attachments\">\n> & {\n readonly attachments?: readonly ImageAttachment[];\n};\n\nconst sessionInputResponseBase = {\n requestId: z.string().min(1).describe(\"Pending provider input request ID.\"),\n};\n\n/** Validates an option selection or freeform answer to one provider input request. */\nexport const sessionInputResponseSchema = z.union([\n z.strictObject({\n ...sessionInputResponseBase,\n optionId: z.string().min(1).describe(\"Selected option ID.\"),\n text: z.never().optional().describe(\"Absent for an option selection.\"),\n }),\n z.strictObject({\n ...sessionInputResponseBase,\n optionId: z.never().optional().describe(\"Absent for a freeform answer.\"),\n text: z.string().min(1).describe(\"Freeform answer text.\"),\n }),\n]);\n/** A response to one pending provider input request. */\nexport type SessionInputResponse = Readonly<z.input<typeof sessionInputResponseSchema>>;\n\n/** Validates responses submitted to pending provider input requests. */\nexport const submitSessionInputRequestSchema = z.strictObject({\n executionId: z\n .string()\n .min(1)\n .describe(\"Observed provider session ID; stale input responses are rejected.\"),\n inputResponses: z\n .array(sessionInputResponseSchema)\n .min(1)\n .readonly()\n .describe(\"Responses to pending human-input requests.\"),\n});\n/** Responses submitted to pending provider input requests. */\nexport interface SubmitSessionInputRequest {\n readonly executionId: string;\n readonly inputResponses: readonly SessionInputResponse[];\n}\n\n/** Validates an execution-aware session control request. */\nexport const controlSessionRequestSchema = z.strictObject({\n executionId: z\n .string()\n .min(1)\n .optional()\n .describe(\"Observed provider session ID; guards against a replaced execution.\"),\n turnId: z.string().min(1).optional().describe(\"Observed turn ID for cooperative interruption.\"),\n});\n/** Execution and turn observed before requesting a session control operation. */\nexport type ControlSessionRequest = Readonly<z.input<typeof controlSessionRequestSchema>>;\n\n/** Validates an authenticated answer to a workflow question. */\nexport const answerSessionQuestionRequestSchema = z.strictObject({\n questionId: taskIdSchema.describe(\"Question Task belonging to this operator session.\"),\n answer: z.string().min(1).max(16000).describe(\"Authenticated immutable human answer.\"),\n});\n/** Authenticated answer to a workflow question in a session. */\nexport interface AnswerSessionQuestionRequest {\n readonly questionId: TaskId;\n readonly answer: string;\n}\n\n/** Validates the current operator-facing projection of a Factory session. */\nexport const sessionViewSchema = z.strictObject({\n session: agentSessionSchema.describe(\"Durable interaction binding.\"),\n task: taskSchema.nullable().describe(\"Current task state, if workflow-backed.\"),\n dependencyTaskIds: z\n .array(taskIdSchema)\n .readonly()\n .optional()\n .describe(\"Read-only current Task dependencies projected from its authoritative task graph.\"),\n execution: executionReferenceSchema\n .nullable()\n .describe(\"Current execution; may change after recovery.\"),\n activeAgent: z\n .string()\n .optional()\n .describe(\"Agent executing the selected work in this conversation.\"),\n source: z.string().optional().describe(\"Original trigger of automatically started work.\"),\n prUrl: z.string().optional().describe(\"Pull request associated with the conversation.\"),\n attention: z\n .enum([\"question\", \"failed\", \"stalled\", \"review\", \"conversation\"])\n .optional()\n .describe(\n \"Current human action: answer a question, inspect failed or stalled work, review a ready Change, or continue an external conversation.\",\n ),\n canFollowUp: z\n .boolean()\n .optional()\n .describe(\"Whether completed work can start a budgeted discussion in this conversation.\"),\n hasWorkflowFailure: z\n .boolean()\n .optional()\n .describe(\"Whether delegated workflow work has failed, independently of a pending question.\"),\n canCancel: z\n .boolean()\n .optional()\n .describe(\n \"Whether cancellation is available for the conversation or its delegated workflow work.\",\n ),\n history: z\n .array(\n z.strictObject({\n taskId: taskIdSchema.optional().describe(\"Task owning this execution, if any.\"),\n agent: z.string().describe(\"Agent that owns the provider execution.\"),\n message: z.string().describe(\"Initial request displayed for this execution.\"),\n attachments: imageAttachmentsSchema\n .optional()\n .describe(\"Images accompanying this execution's initial user request.\"),\n execution: executionReferenceSchema.describe(\"Authorized provider execution to replay.\"),\n }),\n )\n .readonly()\n .optional()\n .describe(\"Earlier executions, in conversation order, including replacement attempts.\"),\n relatedTasks: z\n .array(taskSchema)\n .readonly()\n .optional()\n .describe(\"Work linked to this conversation, including specialist delegations.\"),\n question: taskSchema\n .nullable()\n .describe(\"Open Factory question requiring an authenticated answer.\"),\n});\n/** The current operator-facing projection of a Factory session. */\nexport type SessionView = z.infer<typeof sessionViewSchema>;\n\n/** Validates a cursor-paginated page of operator-facing sessions. */\nexport const sessionPageSchema = z.strictObject({\n sessions: z.array(sessionViewSchema).readonly().describe(\"Sessions in this page.\"),\n nextCursor: z\n .string()\n .min(1)\n .nullable()\n .default(null)\n .describe(\"Opaque cursor to pass unchanged for the next page, or null after the final page.\"),\n totalCount: z\n .number()\n .int()\n .nonnegative()\n .optional()\n .describe(\"Total matching sessions when explicitly requested.\"),\n});\n/** Cursor-paginated operator-facing sessions. */\nexport type SessionPage = z.infer<typeof sessionPageSchema>;\n\n/** Validates one configured repository exposed by the operator API. */\nexport const repositorySummarySchema = z.strictObject({\n id: repositoryIdSchema.describe(\"Stable configured repository identifier.\"),\n slug: repositorySlugSchema.describe(\"Configured owner/repository slug.\"),\n});\n/** Configured repository exposed by the operator API. */\nexport type RepositorySummary = z.infer<typeof repositorySummarySchema>;\n\n/** Validates repository slugs and their stable identifiers. */\nexport const repositoryDetailsSchema = z.strictObject({\n repositories: z\n .array(repositorySlugSchema)\n .readonly()\n .describe(\"Configured owner/repository slugs.\"),\n details: z\n .array(repositorySummarySchema)\n .readonly()\n .default([])\n .describe(\"Stable identifiers and slugs for configured repositories.\"),\n});\n/** Repository slugs and their stable configured identifiers. */\nexport type RepositoryDetails = z.infer<typeof repositoryDetailsSchema>;\n\n/** Validates a locally retained follow-up awaiting confirmed API acceptance. */\nexport const pendingFollowUpSchema = z\n .strictObject({\n sessionId: agentSessionIdSchema.describe(\"Conversation containing this follow-up.\"),\n operationId: z\n .string()\n .min(1)\n .max(200)\n .describe(\"Stable operation id retained until acceptance is confirmed.\"),\n executionId: z\n .string()\n .nullable()\n .describe(\"Execution observed before sending, or null before execution starts.\"),\n message: agentSessionMessageSchema,\n attachments: imageAttachmentsSchema\n .optional()\n .describe(\"Uploaded images accompanying this message.\"),\n turnPolicy: z.enum([\"steer\", \"queue\"]).describe(\"Requested turn policy.\"),\n })\n .refine(hasMessageContent, \"Enter a message or attach an image\");\n/** A locally retained follow-up awaiting confirmed API acceptance. */\nexport type PendingFollowUp = Readonly<\n Omit<z.output<typeof pendingFollowUpSchema>, \"attachments\">\n> & {\n readonly attachments?: readonly ImageAttachment[];\n};\n"],"mappings":"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"}
|
package/dist/api.d.mts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { InboxActivity, InboxActivityItem, inboxActivityItemSchema, inboxActivitySchema } from "./inbox-activity.mjs";
|
|
2
|
+
import { AgentModelConfig, ModelSettings, UpdateModelDefaults, agentModelConfigSchema, modelSettingsSchema, updateModelDefaultsSchema } from "./model-settings.mjs";
|
|
3
|
+
import { SessionPreview, SessionPreviews, sessionPreviewSchema, sessionPreviewsSchema } from "./session-previews.mjs";
|
|
4
|
+
import { SessionReview, SessionReviewCheck, SessionReviewIssue, SessionReviewScreenshot, sessionReviewCheckSchema, sessionReviewIssueSchema, sessionReviewSchema, sessionReviewScreenshotSchema } from "./session-review.mjs";
|
|
5
|
+
import { WorkspaceGitFilesOptions, workspaceGitFilesScript } from "./workspace-files-git.mjs";
|
|
6
|
+
import { WorkspaceFileEntry, WorkspaceFiles, WorkspaceFilesRequest, workspaceFileContentSchema, workspaceFileEntrySchema, workspaceFilesRequestSchema, workspaceFilesSchema, workspacePathSchema } from "./workspace-files.mjs";
|
|
1
7
|
import { Signal } from "./schema/signal.mjs";
|
|
2
8
|
import { Repository, RepositorySlug } from "./schema/repository.mjs";
|
|
3
9
|
import { ExecutionReference, Task } from "./schema/task.mjs";
|
|
@@ -28,14 +34,43 @@ interface FactoryApiForwardInput {
|
|
|
28
34
|
readonly path: string;
|
|
29
35
|
readonly request: Request;
|
|
30
36
|
}
|
|
37
|
+
/** Identifies a file inspection in an authorized execution workspace. */
|
|
38
|
+
interface FactoryApiWorkspaceFilesInput extends FactoryApiWorkspaceDiffInput {
|
|
39
|
+
readonly query: WorkspaceFilesRequest;
|
|
40
|
+
}
|
|
31
41
|
/** Identifies the active execution whose workspace diff the Factory API requests. */
|
|
32
42
|
interface FactoryApiWorkspaceDiffInput {
|
|
33
43
|
readonly session: AgentSession;
|
|
34
44
|
readonly execution: ExecutionReference;
|
|
35
45
|
readonly signal: AbortSignal;
|
|
36
46
|
}
|
|
47
|
+
/** Authorized session projection supplied to an application-owned review reader. */
|
|
48
|
+
interface FactoryApiSessionReviewInput {
|
|
49
|
+
readonly current: SessionView;
|
|
50
|
+
/** Authorized current Task snapshots, including delegated workflow-owned work. */
|
|
51
|
+
readonly tasks: readonly Task[];
|
|
52
|
+
readonly signal: AbortSignal;
|
|
53
|
+
}
|
|
54
|
+
/** Authorized work supplied to an application-owned preview reader. */
|
|
55
|
+
interface FactoryApiSessionPreviewsInput {
|
|
56
|
+
readonly current: SessionView;
|
|
57
|
+
readonly tasks: readonly Task[];
|
|
58
|
+
readonly signal: AbortSignal;
|
|
59
|
+
}
|
|
60
|
+
/** Authenticated caller and repository scope supplied to an external activity reader. */
|
|
61
|
+
interface FactoryApiInboxActivityInput {
|
|
62
|
+
/** Authenticated caller; the reader must apply its application's source access policy. */
|
|
63
|
+
readonly principal: ApiPrincipal;
|
|
64
|
+
/** Configured repositories that have not been disabled. Never expand this scope. */
|
|
65
|
+
readonly repositories: readonly RepositorySlug[];
|
|
66
|
+
readonly signal: AbortSignal;
|
|
67
|
+
}
|
|
37
68
|
/** Application-owned dependencies and authorization policies for the Factory HTTP API. */
|
|
38
69
|
interface FactoryApiOptions {
|
|
70
|
+
/** Optional application-owned catalogs; the start adapter must honor each persisted model choice. */
|
|
71
|
+
agentModels?: readonly AgentModelConfig[];
|
|
72
|
+
/** Explicit policy for saving shared repository defaults; absent denies mutations. */
|
|
73
|
+
canEditModelDefaults?(principal: ApiPrincipal, repository: Repository): Promise<boolean>;
|
|
39
74
|
stores: FactoryStores;
|
|
40
75
|
agents: readonly ApiAgentInput[];
|
|
41
76
|
routes: AgentRouteRegistry;
|
|
@@ -50,7 +85,7 @@ interface FactoryApiOptions {
|
|
|
50
85
|
}, task: Task): Promise<boolean>;
|
|
51
86
|
/** Exposed conversational agent used for separately budgeted follow-up investigations. */
|
|
52
87
|
continuationAgent?: string;
|
|
53
|
-
/** Application-owned
|
|
88
|
+
/** Application-owned validation and launch for a stopped intake attempt, including supported Signal sources. */
|
|
54
89
|
retryIntake?(signal: Signal, options: {
|
|
55
90
|
expectedAttempt: number;
|
|
56
91
|
by: string;
|
|
@@ -59,7 +94,15 @@ interface FactoryApiOptions {
|
|
|
59
94
|
ensureRepository(slug: RepositorySlug): Promise<Repository>;
|
|
60
95
|
start(input: FactoryApiStartInput): Promise<ExecutionReference>;
|
|
61
96
|
forward(input: FactoryApiForwardInput): Promise<Response>;
|
|
97
|
+
/** Optional evidence reader; owns source selection, image access, and response limits. */
|
|
98
|
+
sessionReview?(input: FactoryApiSessionReviewInput): Promise<SessionReview>;
|
|
99
|
+
/** Optional read-only preview reader; owns source selection, link access, expiry, and limits. */
|
|
100
|
+
sessionPreviews?(input: FactoryApiSessionPreviewsInput): Promise<SessionPreviews>;
|
|
101
|
+
/** Optional external attention reader; owns caller authorization, sources, caching, and limits. */
|
|
102
|
+
inboxActivity?(input: FactoryApiInboxActivityInput): Promise<InboxActivity>;
|
|
62
103
|
workspaceDiff?(input: FactoryApiWorkspaceDiffInput): Promise<WorkspaceDiff>;
|
|
104
|
+
/** Optional provider-neutral reader for files and directories at immutable revisions. */
|
|
105
|
+
workspaceFiles?(input: FactoryApiWorkspaceFilesInput): Promise<WorkspaceFiles>;
|
|
63
106
|
reportError?(error: unknown, context: {
|
|
64
107
|
method: string;
|
|
65
108
|
path: string;
|
|
@@ -73,5 +116,5 @@ interface FactoryApi {
|
|
|
73
116
|
/** Creates the authenticated request handler for the public Factory HTTP API. */
|
|
74
117
|
declare function createFactoryApi(options: FactoryApiOptions): FactoryApi;
|
|
75
118
|
//#endregion
|
|
76
|
-
export { type AgentSession, type AgentSessionId, type AnswerSessionQuestionRequest, type ApiAgent, type ApiAgentInput, type ApiPrincipal, type ControlSessionRequest, type CreateSessionRequest, type DirectAgentSession, type ExternalAgentSession, FactoryApi, FactoryApiForwardInput, FactoryApiOptions, FactoryApiStartInput, FactoryApiWorkspaceDiffInput, ImageInputError, type RepositoryDetails, type RepositorySummary, type ResolveImageMessageInput, type ResolveImageMessageStores, type ResolvedImageMessage, type ResolvedImageMessagePart, type SendSessionMessageRequest, SessionConflictError, type SessionInputResponse, type SessionPage, type SessionView, type SubmitSessionInputRequest, type TaskAgentSession, type UnavailableWorkspaceDiffInput, type WorkspaceBaseBlob, type WorkspaceBaseEntry, type WorkspaceDiff, type WorkspaceDiffAssemblyOptions, type WorkspaceDiffFile, type WorkspaceSnapshot, agentSessionIdSchema, agentSessionSchema, answerSessionQuestionRequestSchema, apiAgentSchema, assembleWorkspaceDiff, controlSessionRequestSchema, createFactoryApi, createSessionRequestSchema, imagePartFilename, repositoryDetailsSchema, repositorySummarySchema, resolveImageMessage, sendSessionMessageRequestSchema, sessionInputResponseSchema, sessionPageSchema, sessionViewSchema, submitSessionInputRequestSchema, unavailableWorkspaceDiff, workspaceDiffFileSchema, workspaceDiffSchema, workspaceSnapshotSchema, workspaceSnapshotScript };
|
|
119
|
+
export { type AgentModelConfig, type AgentSession, type AgentSessionId, type AnswerSessionQuestionRequest, type ApiAgent, type ApiAgentInput, type ApiPrincipal, type ControlSessionRequest, type CreateSessionRequest, type DirectAgentSession, type ExternalAgentSession, FactoryApi, FactoryApiForwardInput, FactoryApiInboxActivityInput, FactoryApiOptions, FactoryApiSessionPreviewsInput, FactoryApiSessionReviewInput, FactoryApiStartInput, FactoryApiWorkspaceDiffInput, FactoryApiWorkspaceFilesInput, ImageInputError, type InboxActivity, type InboxActivityItem, type ModelSettings, type RepositoryDetails, type RepositorySummary, type ResolveImageMessageInput, type ResolveImageMessageStores, type ResolvedImageMessage, type ResolvedImageMessagePart, type SendSessionMessageRequest, SessionConflictError, type SessionInputResponse, type SessionPage, type SessionPreview, type SessionPreviews, type SessionReview, type SessionReviewCheck, type SessionReviewIssue, type SessionReviewScreenshot, type SessionView, type SubmitSessionInputRequest, type TaskAgentSession, type UnavailableWorkspaceDiffInput, type UpdateModelDefaults, type WorkspaceBaseBlob, type WorkspaceBaseEntry, type WorkspaceDiff, type WorkspaceDiffAssemblyOptions, type WorkspaceDiffFile, type WorkspaceFileEntry, type WorkspaceFiles, type WorkspaceFilesRequest, type WorkspaceGitFilesOptions, type WorkspaceSnapshot, agentModelConfigSchema, agentSessionIdSchema, agentSessionSchema, answerSessionQuestionRequestSchema, apiAgentSchema, assembleWorkspaceDiff, controlSessionRequestSchema, createFactoryApi, createSessionRequestSchema, imagePartFilename, inboxActivityItemSchema, inboxActivitySchema, modelSettingsSchema, repositoryDetailsSchema, repositorySummarySchema, resolveImageMessage, sendSessionMessageRequestSchema, sessionInputResponseSchema, sessionPageSchema, sessionPreviewSchema, sessionPreviewsSchema, sessionReviewCheckSchema, sessionReviewIssueSchema, sessionReviewSchema, sessionReviewScreenshotSchema, sessionViewSchema, submitSessionInputRequestSchema, unavailableWorkspaceDiff, updateModelDefaultsSchema, workspaceDiffFileSchema, workspaceDiffSchema, workspaceFileContentSchema, workspaceFileEntrySchema, workspaceFilesRequestSchema, workspaceFilesSchema, workspaceGitFilesScript, workspacePathSchema, workspaceSnapshotSchema, workspaceSnapshotScript };
|
|
77
120
|
//# sourceMappingURL=api.d.mts.map
|
package/dist/api.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { signalIdSchema, taskIdSchema } from "./schema/id.mjs";
|
|
1
|
+
import { repositoryIdSchema, signalIdSchema, taskIdSchema } from "./schema/id.mjs";
|
|
2
2
|
import { repositorySlugSchema } from "./schema/repository.mjs";
|
|
3
|
+
import { parseAgentRouteBinding } from "./schema/agent-route.mjs";
|
|
3
4
|
import { taskStateSchema } from "./schema/task.mjs";
|
|
4
5
|
import { InvalidTransitionError } from "./schema/transitions.mjs";
|
|
5
6
|
import { readEvents } from "./client-events.mjs";
|
|
@@ -11,10 +12,16 @@ import { BudgetExhaustedError, DispatchRefusedError, dispatchTask } from "./disp
|
|
|
11
12
|
import { ApprovalAccessError, createApprovalAccess } from "./approval-access.mjs";
|
|
12
13
|
import { agentSessionIdSchema, agentSessionSchema } from "./schema/session.mjs";
|
|
13
14
|
import { ApprovalError, ImageInputError, SessionConflictError } from "./store/engine.mjs";
|
|
15
|
+
import { inboxActivityItemSchema, inboxActivitySchema } from "./inbox-activity.mjs";
|
|
16
|
+
import { agentModelConfigSchema, modelSettingsSchema, updateModelDefaultsSchema } from "./model-settings.mjs";
|
|
17
|
+
import { sessionPreviewSchema, sessionPreviewsSchema } from "./session-previews.mjs";
|
|
18
|
+
import { sessionReviewCheckSchema, sessionReviewIssueSchema, sessionReviewSchema, sessionReviewScreenshotSchema } from "./session-review.mjs";
|
|
19
|
+
import { workspaceFileContentSchema, workspaceFileEntrySchema, workspaceFilesRequestSchema, workspaceFilesSchema, workspacePathSchema } from "./workspace-files.mjs";
|
|
14
20
|
import { intakeViewSchema, retryIntakeSchema } from "./intake-contracts.mjs";
|
|
15
21
|
import { answerSessionQuestionRequestSchema, apiAgentSchema, controlSessionRequestSchema, createSessionRequestSchema, repositoryDetailsSchema, repositorySummarySchema, sendSessionMessageRequestSchema, sessionInputResponseSchema, sessionPageSchema, sessionViewSchema, submitSessionInputRequestSchema } from "./api-contracts.mjs";
|
|
16
22
|
import { unavailableWorkspaceDiff, workspaceDiffFileSchema, workspaceDiffSchema } from "./workspace-diff.mjs";
|
|
17
23
|
import { taskGraphViewSchema } from "./task-graph-view.mjs";
|
|
24
|
+
import { workspaceGitFilesScript } from "./workspace-files-git.mjs";
|
|
18
25
|
import { TaskGraphAccessError, readSessionGraph } from "./api-task-graph.mjs";
|
|
19
26
|
import { resolveImageMessage } from "./api-images.mjs";
|
|
20
27
|
import { workspaceSnapshotSchema, workspaceSnapshotScript } from "./workspace-snapshot.mjs";
|
|
@@ -41,6 +48,14 @@ function attention(task, change) {
|
|
|
41
48
|
function createFactoryApi(options) {
|
|
42
49
|
const { stores } = options;
|
|
43
50
|
const agents = options.agents.map((agent) => apiAgentSchema.parse(agent));
|
|
51
|
+
const agentModels = (options.agentModels ?? []).map((entry) => agentModelConfigSchema.parse(entry));
|
|
52
|
+
if (new Set(agentModels.map((entry) => entry.agent)).size !== agentModels.length) throw new Error("Duplicate agent model catalog");
|
|
53
|
+
function selectModel(agent, requested, defaults) {
|
|
54
|
+
const catalog = agentModels.find((entry) => entry.agent === agent);
|
|
55
|
+
const model = requested ?? defaults?.[agent] ?? catalog?.defaultModel;
|
|
56
|
+
if (model !== void 0 && !catalog?.models.some((entry) => entry.id === model)) throw new ApiError(400, `Model is not available for ${agent}. Choose an advertised model.`);
|
|
57
|
+
return model;
|
|
58
|
+
}
|
|
44
59
|
if (new Set(agents.map((agent) => agent.id)).size !== agents.length) throw new Error("Duplicate API agent");
|
|
45
60
|
if (options.continuationAgent !== void 0 && !agents.some((agent) => agent.id === options.continuationAgent && agent.route === void 0 && agent.canStart)) throw new Error("continuationAgent must be a directly startable conversation agent");
|
|
46
61
|
for (const agent of agents) if (agent.route !== void 0 && options.routes.get(agent.route)?.agent !== agent.id) throw new Error(`API agent ${agent.id} must select one of its registered routes`);
|
|
@@ -413,6 +428,7 @@ function createFactoryApi(options) {
|
|
|
413
428
|
async function assertRepository(id) {
|
|
414
429
|
const repository = await stores.repositories.get(id);
|
|
415
430
|
if (repository === null || !repository.enabled || !options.repositories.includes(repository.slug)) throw new ApiError(403, "The session repository is no longer enabled and configured");
|
|
431
|
+
return repository;
|
|
416
432
|
}
|
|
417
433
|
async function owned(id, owner) {
|
|
418
434
|
const session = await stores.sessions.get(agentSessionIdSchema.parse(id));
|
|
@@ -479,13 +495,14 @@ function createFactoryApi(options) {
|
|
|
479
495
|
if (agent.requiresChange && input.changeId === void 0) throw new ApiError(400, `${agent.id} requires an existing changeId`);
|
|
480
496
|
const slug = input.repository === void 0 ? void 0 : repositorySlugSchema.parse(input.repository.toLowerCase());
|
|
481
497
|
if (slug !== void 0 && !options.repositories.includes(slug)) throw new ApiError(403, "Repository is not configured");
|
|
482
|
-
const repository = slug === void 0 ? void 0 : await options.ensureRepository(slug);
|
|
483
|
-
if (repository !== void 0) await assertRepository(repository.id);
|
|
498
|
+
const repository = slug === void 0 ? void 0 : await assertRepository((await options.ensureRepository(slug)).id);
|
|
484
499
|
if (input.changeId !== void 0) {
|
|
485
500
|
const change = await stores.changes.get(input.changeId);
|
|
486
501
|
if (change === null || change.repositoryId !== repository?.id) throw new ApiError(400, "changeId must identify a change in the selected repository");
|
|
487
502
|
if (change.state !== "verifying" && change.state !== "ready") throw new ApiError(409, "Change is no longer open for work");
|
|
488
503
|
}
|
|
504
|
+
const existing = await stores.sessions.getByOperation(owner, input.operationId);
|
|
505
|
+
const model = existing && input.model === void 0 ? existing.model : selectModel(agent.id, input.model, repository?.modelDefaults?.agents);
|
|
489
506
|
let session = await stores.sessions.create({
|
|
490
507
|
operationId: input.operationId,
|
|
491
508
|
owner,
|
|
@@ -494,6 +511,7 @@ function createFactoryApi(options) {
|
|
|
494
511
|
route: agent.route,
|
|
495
512
|
message: input.message,
|
|
496
513
|
changeId: input.changeId,
|
|
514
|
+
model,
|
|
497
515
|
...input.attachments?.length ? { attachments: input.attachments } : {}
|
|
498
516
|
});
|
|
499
517
|
if (agent.route !== void 0 && session.taskId === void 0) {
|
|
@@ -539,10 +557,57 @@ function createFactoryApi(options) {
|
|
|
539
557
|
changeId: input.changeId,
|
|
540
558
|
dedupeKey: `api:${session.id}`
|
|
541
559
|
});
|
|
560
|
+
if (session.model) await stores.tasks.pinModel(task.id, {
|
|
561
|
+
attempt: task.attempt,
|
|
562
|
+
model: session.model
|
|
563
|
+
});
|
|
542
564
|
session = await stores.sessions.bind(session.id, { taskId: task.id });
|
|
543
565
|
}
|
|
544
566
|
return json(await launch(session), 202);
|
|
545
567
|
}
|
|
568
|
+
/**
|
|
569
|
+
* Starts a deepsec security scan of a repository as a background Task,
|
|
570
|
+
* the same way `factory scan` does, or returns the already-active scan for
|
|
571
|
+
* that repository instead of starting a duplicate one.
|
|
572
|
+
*/
|
|
573
|
+
async function startSecurityScan(rawId, owner) {
|
|
574
|
+
const repositoryId = repositoryIdSchema.parse(rawId);
|
|
575
|
+
const repository = await stores.repositories.get(repositoryId);
|
|
576
|
+
if (!repository) throw new ApiError(404, "Repository not found");
|
|
577
|
+
await assertRepository(repositoryId);
|
|
578
|
+
const active = (await stores.tasks.list()).find((task) => task.kind === "security_scan" && task.repositoryIds.includes(repository.id) && ![
|
|
579
|
+
"succeeded",
|
|
580
|
+
"failed",
|
|
581
|
+
"cancelled"
|
|
582
|
+
].includes(task.state));
|
|
583
|
+
if (active) return json({
|
|
584
|
+
taskId: active.id,
|
|
585
|
+
reused: true
|
|
586
|
+
}, 202);
|
|
587
|
+
const route = options.routes.get(parseAgentRouteBinding({
|
|
588
|
+
id: "security-scan",
|
|
589
|
+
version: 1
|
|
590
|
+
}));
|
|
591
|
+
if (!route) throw new ApiError(409, "This factory has no security-scan route configured");
|
|
592
|
+
const task = await stores.tasks.create({
|
|
593
|
+
repositoryIds: [repository.id],
|
|
594
|
+
kind: "security_scan",
|
|
595
|
+
work: routeTaskWork({
|
|
596
|
+
route,
|
|
597
|
+
title: `Security scan of ${repository.slug}`,
|
|
598
|
+
input: { repositoryId: repository.id }
|
|
599
|
+
}),
|
|
600
|
+
origin: { operator: owner },
|
|
601
|
+
replyTo: {
|
|
602
|
+
channel: "factory",
|
|
603
|
+
address: repository.slug
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
return json({
|
|
607
|
+
taskId: task.id,
|
|
608
|
+
reused: false
|
|
609
|
+
}, 202);
|
|
610
|
+
}
|
|
546
611
|
async function continuationBrief(session, current, message, taskId) {
|
|
547
612
|
const continuation = session.continuations?.find((item) => item.taskId === taskId);
|
|
548
613
|
const saved = continuation?.context;
|
|
@@ -625,21 +690,22 @@ function createFactoryApi(options) {
|
|
|
625
690
|
}
|
|
626
691
|
async function materializedTranscript(session, task, agent, execution, signal) {
|
|
627
692
|
const cached = await stores.transcripts.get(execution);
|
|
628
|
-
if (cached !== null) return cached;
|
|
693
|
+
if (cached !== null && cached.state !== "running" && cached.state !== "connecting") return cached;
|
|
629
694
|
const transcript = new Transcript();
|
|
695
|
+
if (cached !== null) transcript.hydrate(cached);
|
|
630
696
|
const path = `/stream?${new URLSearchParams({
|
|
631
|
-
startIndex:
|
|
697
|
+
startIndex: String(transcript.cursor),
|
|
632
698
|
includeTailIndex: "1"
|
|
633
699
|
})}`;
|
|
634
700
|
const response = await options.forward({
|
|
635
701
|
session: executionSession(session, task, agent),
|
|
636
702
|
execution,
|
|
637
703
|
path,
|
|
638
|
-
request: new Request("http://factory/transcript", { signal })
|
|
704
|
+
request: new Request("http://factory/transcript", { signal: AbortSignal.any([signal, AbortSignal.timeout(15e3)]) })
|
|
639
705
|
});
|
|
640
706
|
if (!response.ok || !response.body) {
|
|
641
707
|
await response.body?.cancel();
|
|
642
|
-
throw new ApiError(response.status || 502, "Execution transcript is unavailable");
|
|
708
|
+
throw new ApiError(response.status || 502, response.status === 404 ? "Execution transcript is unavailable on this deployment. It may belong to another deployment or have expired." : "Execution transcript is unavailable");
|
|
643
709
|
}
|
|
644
710
|
const tailValue = response.headers.get("x-eve-stream-tail-index");
|
|
645
711
|
const tail = tailValue === null ? NaN : Number(tailValue);
|
|
@@ -647,7 +713,11 @@ function createFactoryApi(options) {
|
|
|
647
713
|
await response.body.cancel();
|
|
648
714
|
throw new Error("Execution transcript did not include a valid durable cursor");
|
|
649
715
|
}
|
|
650
|
-
for await (const event of readEvents(response.body))
|
|
716
|
+
if (transcript.cursor <= tail) for await (const event of readEvents(response.body)) {
|
|
717
|
+
transcript.accept(event);
|
|
718
|
+
if (transcript.cursor === tail + 1) break;
|
|
719
|
+
}
|
|
720
|
+
else await response.body.cancel();
|
|
651
721
|
if (transcript.cursor !== tail + 1) throw new Error("Execution transcript closed before its durable cursor");
|
|
652
722
|
return stores.transcripts.put(execution, transcript.snapshot());
|
|
653
723
|
}
|
|
@@ -708,6 +778,28 @@ function createFactoryApi(options) {
|
|
|
708
778
|
const url = new URL(request.url);
|
|
709
779
|
const path = url.pathname.replace(/^\/api\/v1\/?/u, "").split("/").filter(Boolean);
|
|
710
780
|
const [resource, id, action] = path;
|
|
781
|
+
if (resource === "models" && path.length === 1 && ["GET", "POST"].includes(request.method)) {
|
|
782
|
+
const update = request.method === "POST" ? updateModelDefaultsSchema.parse(await body(request)) : null;
|
|
783
|
+
const slug = update?.repository ?? (url.searchParams.has("repository") ? repositorySlugSchema.parse(url.searchParams.get("repository")) : null);
|
|
784
|
+
if (slug && !options.repositories.includes(slug)) throw new ApiError(403, "Repository is not configured");
|
|
785
|
+
let repository = slug ? await assertRepository((await options.ensureRepository(slug)).id) : null;
|
|
786
|
+
const canEdit = repository !== null && agentModels.length > 0 && await options.canEditModelDefaults?.(auth, repository) === true;
|
|
787
|
+
if (update) {
|
|
788
|
+
if (!repository || !canEdit) throw new ApiError(403, "Saving model defaults requires an authorized operator");
|
|
789
|
+
for (const [agent, model] of Object.entries(update.defaults)) selectModel(agent, model);
|
|
790
|
+
repository = await stores.repositories.setModelDefaults(repository.id, {
|
|
791
|
+
expectedRevision: update.expectedRevision,
|
|
792
|
+
agents: update.defaults
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
return json(modelSettingsSchema.parse({
|
|
796
|
+
agents: agentModels,
|
|
797
|
+
repository: slug,
|
|
798
|
+
defaults: repository?.modelDefaults?.agents ?? {},
|
|
799
|
+
revision: repository?.modelDefaults?.revision ?? 0,
|
|
800
|
+
canEdit
|
|
801
|
+
}));
|
|
802
|
+
}
|
|
711
803
|
if (path.length > 3) throw new ApiError(404, "API route not found");
|
|
712
804
|
if (resource === "intake") {
|
|
713
805
|
if (!auth.actor || !(options.operators ?? []).includes(auth.actor)) throw new ApiError(403, "Intake requires an individually authenticated configured operator");
|
|
@@ -739,7 +831,7 @@ function createFactoryApi(options) {
|
|
|
739
831
|
if (!signal || !allowed.has(signal.repositoryId)) throw new ApiError(404, "Intake not found");
|
|
740
832
|
const input = retryIntakeSchema.parse(await body(request));
|
|
741
833
|
if (signal.outcome !== "pending" || signal.triage?.state !== "blocked" || signal.triage.attempt !== input.expectedAttempt || tasks.some((task) => task.origin.signalId === signal.id)) throw new ApiError(409, "Only the observed blocked attempt with no linked task can be retried; refresh intake");
|
|
742
|
-
if (!options.retryIntake
|
|
834
|
+
if (!options.retryIntake) throw new ApiError(409, "This factory has no retry launcher for this intake source");
|
|
743
835
|
return json(view(await options.retryIntake(signal, {
|
|
744
836
|
...input,
|
|
745
837
|
by: auth.actor
|
|
@@ -765,6 +857,7 @@ function createFactoryApi(options) {
|
|
|
765
857
|
input: await body(request)
|
|
766
858
|
}));
|
|
767
859
|
}
|
|
860
|
+
if (resource === "repositories" && id && action === "security-scan" && request.method === "POST") return await startSecurityScan(id, auth.id);
|
|
768
861
|
if (resource === "images") {
|
|
769
862
|
if (request.method === "POST" && path.length === 1) {
|
|
770
863
|
const input = imageUploadSchema.parse(await body(request, 4 * Math.ceil(MAX_IMAGE_BYTES / 3) + 2048));
|
|
@@ -785,6 +878,33 @@ function createFactoryApi(options) {
|
|
|
785
878
|
throw new ApiError(404, "API route not found");
|
|
786
879
|
}
|
|
787
880
|
if (request.method === "GET" && path.length === 1) {
|
|
881
|
+
if (resource === "inbox-activity") {
|
|
882
|
+
if (!options.inboxActivity) return json({
|
|
883
|
+
state: "unavailable",
|
|
884
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
885
|
+
reason: "External activity is not configured."
|
|
886
|
+
});
|
|
887
|
+
const allowedRepositories = async () => {
|
|
888
|
+
const disabled = new Set((await stores.repositories.list()).filter((repo) => !repo.enabled).map((repo) => repo.slug));
|
|
889
|
+
return options.repositories.filter((slug) => !disabled.has(slug));
|
|
890
|
+
};
|
|
891
|
+
const repositories = await allowedRepositories();
|
|
892
|
+
const result = inboxActivitySchema.parse(await options.inboxActivity({
|
|
893
|
+
principal: auth,
|
|
894
|
+
repositories,
|
|
895
|
+
signal: request.signal
|
|
896
|
+
}));
|
|
897
|
+
if (result.state === "ready") {
|
|
898
|
+
const allowed = new Set(await allowedRepositories());
|
|
899
|
+
const ids = /* @__PURE__ */ new Set();
|
|
900
|
+
for (const item of result.items) {
|
|
901
|
+
if (!repositories.includes(item.repository) || !allowed.has(item.repository)) throw new ApiError(403, "Activity repository is not available");
|
|
902
|
+
if (ids.has(item.id)) throw new ApiError(502, "Activity contains duplicate identities");
|
|
903
|
+
ids.add(item.id);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
return json(result);
|
|
907
|
+
}
|
|
788
908
|
if (resource === "agents") return json({ agents });
|
|
789
909
|
if (resource === "repositories") return json({
|
|
790
910
|
repositories: options.repositories,
|
|
@@ -863,6 +983,75 @@ function createFactoryApi(options) {
|
|
|
863
983
|
if (latest?.execution?.sessionId !== execution.sessionId || latest.execution.provider !== execution.provider) throw new ApiError(409, "Execution changed; refresh the graph.");
|
|
864
984
|
return json(snapshot);
|
|
865
985
|
}
|
|
986
|
+
if (request.method === "GET" && (action === "review" || action === "previews")) {
|
|
987
|
+
const current = await view(session, void 0, "summary");
|
|
988
|
+
const executionId = current.execution?.sessionId ?? null;
|
|
989
|
+
if (url.searchParams.get("executionId") !== (executionId ?? "")) throw new ApiError(409, "Execution changed; refresh the session before reviewing work");
|
|
990
|
+
const reader = action === "review" ? options.sessionReview : options.sessionPreviews;
|
|
991
|
+
if (!reader) return json({
|
|
992
|
+
state: "unavailable",
|
|
993
|
+
executionId,
|
|
994
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
995
|
+
reason: action === "review" ? "Review evidence is not configured for this factory." : "Live previews are not configured for this factory."
|
|
996
|
+
});
|
|
997
|
+
const reviewTasks = async (value) => {
|
|
998
|
+
const delegated = value.session.external ? [] : workflowTasks(value.session, await stores.tasks.forReplyTo({
|
|
999
|
+
channel: "api",
|
|
1000
|
+
address: value.session.id
|
|
1001
|
+
}));
|
|
1002
|
+
return [...new Map([
|
|
1003
|
+
...value.task ? [value.task] : [],
|
|
1004
|
+
...value.relatedTasks ?? [],
|
|
1005
|
+
...delegated
|
|
1006
|
+
].map((task) => [task.id, task])).values()].sort((a, b) => a.createdAt.localeCompare(b.createdAt) || a.id.localeCompare(b.id));
|
|
1007
|
+
};
|
|
1008
|
+
const tasks = await reviewTasks(current);
|
|
1009
|
+
const identity = (value, work) => JSON.stringify([
|
|
1010
|
+
value.execution,
|
|
1011
|
+
value.task?.id,
|
|
1012
|
+
work.map((task) => [
|
|
1013
|
+
task.id,
|
|
1014
|
+
task.attempt,
|
|
1015
|
+
task.execution,
|
|
1016
|
+
task.changeId,
|
|
1017
|
+
task.repositoryIds
|
|
1018
|
+
])
|
|
1019
|
+
]);
|
|
1020
|
+
const result = (action === "review" ? sessionReviewSchema : sessionPreviewsSchema).parse(await reader({
|
|
1021
|
+
current,
|
|
1022
|
+
tasks,
|
|
1023
|
+
signal: request.signal
|
|
1024
|
+
}));
|
|
1025
|
+
const latest = await view(await owned(id, auth.id), void 0, "summary");
|
|
1026
|
+
if (identity(current, tasks) !== identity(latest, await reviewTasks(latest))) throw new ApiError(409, "Execution changed; refresh the session before reviewing work");
|
|
1027
|
+
if (result.executionId !== executionId) throw new Error("Review reader returned a different execution");
|
|
1028
|
+
return json(result);
|
|
1029
|
+
}
|
|
1030
|
+
if (request.method === "GET" && action === "files") {
|
|
1031
|
+
const query = workspaceFilesRequestSchema.parse({
|
|
1032
|
+
path: url.searchParams.get("path") ?? "",
|
|
1033
|
+
...url.searchParams.has("revision") ? { revision: url.searchParams.get("revision") } : {}
|
|
1034
|
+
});
|
|
1035
|
+
const current = await view(session, void 0, "summary");
|
|
1036
|
+
const execution = current.execution;
|
|
1037
|
+
if (url.searchParams.get("executionId") !== (execution?.sessionId ?? "")) throw new ApiError(409, "Execution changed; refresh the session before browsing files");
|
|
1038
|
+
if (!execution || !options.workspaceFiles) return json({
|
|
1039
|
+
state: "unavailable",
|
|
1040
|
+
path: query.path,
|
|
1041
|
+
executionId: execution?.sessionId ?? null,
|
|
1042
|
+
reason: execution ? "File browsing is not configured for this factory." : "The workspace is not available yet."
|
|
1043
|
+
});
|
|
1044
|
+
const result = workspaceFilesSchema.parse(await options.workspaceFiles({
|
|
1045
|
+
session: executionSession(session, current.task),
|
|
1046
|
+
execution,
|
|
1047
|
+
query,
|
|
1048
|
+
signal: request.signal
|
|
1049
|
+
}));
|
|
1050
|
+
const latest = (await view(await stores.sessions.get(session.id) ?? session, void 0, "summary")).execution;
|
|
1051
|
+
if (latest?.sessionId !== execution.sessionId || latest.provider !== execution.provider) throw new ApiError(409, "Execution changed; refresh the session before browsing files");
|
|
1052
|
+
if (result.executionId !== execution.sessionId || result.path !== query.path || result.state !== "unavailable" && query.revision !== void 0 && result.revision !== query.revision) throw new Error("File inspection returned a different execution, path, or revision");
|
|
1053
|
+
return json(result);
|
|
1054
|
+
}
|
|
866
1055
|
if (request.method === "GET" && action === "diff") {
|
|
867
1056
|
const current = await view(session, void 0, "summary");
|
|
868
1057
|
const execution = current.execution;
|
|
@@ -1082,6 +1271,6 @@ async function body(request, limit = 64e3) {
|
|
|
1082
1271
|
}
|
|
1083
1272
|
}
|
|
1084
1273
|
//#endregion
|
|
1085
|
-
export { ImageInputError, SessionConflictError, agentSessionIdSchema, agentSessionSchema, answerSessionQuestionRequestSchema, apiAgentSchema, assembleWorkspaceDiff, controlSessionRequestSchema, createFactoryApi, createSessionRequestSchema, imagePartFilename, repositoryDetailsSchema, repositorySummarySchema, resolveImageMessage, sendSessionMessageRequestSchema, sessionInputResponseSchema, sessionPageSchema, sessionViewSchema, submitSessionInputRequestSchema, unavailableWorkspaceDiff, workspaceDiffFileSchema, workspaceDiffSchema, workspaceSnapshotSchema, workspaceSnapshotScript };
|
|
1274
|
+
export { ImageInputError, SessionConflictError, agentModelConfigSchema, agentSessionIdSchema, agentSessionSchema, answerSessionQuestionRequestSchema, apiAgentSchema, assembleWorkspaceDiff, controlSessionRequestSchema, createFactoryApi, createSessionRequestSchema, imagePartFilename, inboxActivityItemSchema, inboxActivitySchema, modelSettingsSchema, repositoryDetailsSchema, repositorySummarySchema, resolveImageMessage, sendSessionMessageRequestSchema, sessionInputResponseSchema, sessionPageSchema, sessionPreviewSchema, sessionPreviewsSchema, sessionReviewCheckSchema, sessionReviewIssueSchema, sessionReviewSchema, sessionReviewScreenshotSchema, sessionViewSchema, submitSessionInputRequestSchema, unavailableWorkspaceDiff, updateModelDefaultsSchema, workspaceDiffFileSchema, workspaceDiffSchema, workspaceFileContentSchema, workspaceFileEntrySchema, workspaceFilesRequestSchema, workspaceFilesSchema, workspaceGitFilesScript, workspacePathSchema, workspaceSnapshotSchema, workspaceSnapshotScript };
|
|
1086
1275
|
|
|
1087
1276
|
//# sourceMappingURL=api.mjs.map
|