gemi 0.59.0 → 0.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/Agent.d.ts +533 -25
- package/dist/ai/Agent.d.ts.map +1 -1
- package/dist/ai/Agent.test-d.d.ts +2 -0
- package/dist/ai/Agent.test-d.d.ts.map +1 -0
- package/dist/ai/AgentController.d.ts +275 -6
- package/dist/ai/AgentController.d.ts.map +1 -1
- package/dist/ai/AgentProvider.d.ts +255 -0
- package/dist/ai/AgentProvider.d.ts.map +1 -0
- package/dist/ai/Schema.d.ts +125 -0
- package/dist/ai/Schema.d.ts.map +1 -0
- package/dist/ai/Schema.test-d.d.ts +2 -0
- package/dist/ai/Schema.test-d.d.ts.map +1 -0
- package/dist/ai/client/index.d.ts +24 -0
- package/dist/ai/client/index.d.ts.map +1 -0
- package/dist/ai/client/index.js +1053 -0
- package/dist/ai/client/index.js.map +1 -0
- package/dist/ai/client/reducer.d.ts +127 -0
- package/dist/ai/client/reducer.d.ts.map +1 -0
- package/dist/ai/client/reducer.test-d.d.ts +2 -0
- package/dist/ai/client/reducer.test-d.d.ts.map +1 -0
- package/dist/ai/client/sse.d.ts +54 -0
- package/dist/ai/client/sse.d.ts.map +1 -0
- package/dist/ai/example.d.ts +129 -0
- package/dist/ai/example.d.ts.map +1 -0
- package/dist/ai/index.d.ts +35 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +20 -0
- package/dist/ai/index.js.map +23 -0
- package/dist/ai/live/harness.d.ts +137 -0
- package/dist/ai/live/harness.d.ts.map +1 -0
- package/dist/ai/providers/call.d.ts +42 -0
- package/dist/ai/providers/call.d.ts.map +1 -0
- package/dist/ai/providers/capabilities.d.ts +50 -0
- package/dist/ai/providers/capabilities.d.ts.map +1 -0
- package/dist/ai/providers/errors.d.ts +37 -0
- package/dist/ai/providers/errors.d.ts.map +1 -0
- package/dist/ai/providers/fakeProvider.d.ts +35 -0
- package/dist/ai/providers/fakeProvider.d.ts.map +1 -0
- package/dist/ai/providers/http.d.ts +46 -0
- package/dist/ai/providers/http.d.ts.map +1 -0
- package/dist/ai/providers/request.d.ts +69 -0
- package/dist/ai/providers/request.d.ts.map +1 -0
- package/dist/ai/providers/stream.d.ts +42 -0
- package/dist/ai/providers/stream.d.ts.map +1 -0
- package/dist/ai/signing.d.ts +195 -0
- package/dist/ai/signing.d.ts.map +1 -0
- package/dist/ai/store/LiveRuns.d.ts +142 -0
- package/dist/ai/store/LiveRuns.d.ts.map +1 -0
- package/dist/ai/store/MemoryAgentStore.d.ts +61 -0
- package/dist/ai/store/MemoryAgentStore.d.ts.map +1 -0
- package/dist/ai/store/index.d.ts +4 -0
- package/dist/ai/store/index.d.ts.map +1 -0
- package/dist/ai/store/sse.d.ts +58 -0
- package/dist/ai/store/sse.d.ts.map +1 -0
- package/dist/ai/store/stubAgentRun.d.ts +56 -0
- package/dist/ai/store/stubAgentRun.d.ts.map +1 -0
- package/dist/ai/types.d.ts +443 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/useChat.d.ts +253 -7
- package/dist/ai/useChat.d.ts.map +1 -1
- package/dist/bin/gemi.js +500 -16
- package/dist/bin/gemi.js.map +10 -5
- package/dist/chunk-1aqzcgfr.js +5 -0
- package/dist/chunk-1aqzcgfr.js.map +10 -0
- package/dist/{chunk-get4mkx8.js → chunk-1b7e9rj7.js} +2 -2
- package/dist/{chunk-get4mkx8.js.map → chunk-1b7e9rj7.js.map} +1 -1
- package/dist/{chunk-gfma8e03.js → chunk-3aemqfdr.js} +2 -2
- package/dist/{chunk-gfma8e03.js.map → chunk-3aemqfdr.js.map} +1 -1
- package/dist/{chunk-j06g4sqc.js → chunk-528n3vgy.js} +2 -2
- package/dist/{chunk-j06g4sqc.js.map → chunk-528n3vgy.js.map} +1 -1
- package/dist/{chunk-2khdxyjb.js → chunk-57a0nqfj.js} +1 -1
- package/dist/chunk-57a0nqfj.js.map +10 -0
- package/dist/{chunk-c40n5r4v.js → chunk-5mhcwnyd.js} +2 -2
- package/dist/{chunk-c40n5r4v.js.map → chunk-5mhcwnyd.js.map} +1 -1
- package/dist/{chunk-gwchvzdp.js → chunk-71pk1mxx.js} +2 -2
- package/dist/{chunk-gwchvzdp.js.map → chunk-71pk1mxx.js.map} +1 -1
- package/dist/{chunk-spbgpndn.js → chunk-7t1hjs9f.js} +2 -2
- package/dist/{chunk-spbgpndn.js.map → chunk-7t1hjs9f.js.map} +1 -1
- package/dist/{chunk-9gsdcjt7.js → chunk-7xvaace2.js} +3 -3
- package/dist/{chunk-9gsdcjt7.js.map → chunk-7xvaace2.js.map} +1 -1
- package/dist/{chunk-fxy42w6n.js → chunk-8ag0da2s.js} +2 -2
- package/dist/{chunk-fxy42w6n.js.map → chunk-8ag0da2s.js.map} +1 -1
- package/dist/chunk-8r8epsef.js +5 -0
- package/dist/chunk-8r8epsef.js.map +11 -0
- package/dist/chunk-91cj3nxk.js +6 -0
- package/dist/{chunk-txhcx69q.js.map → chunk-91cj3nxk.js.map} +2 -2
- package/dist/{chunk-0fm6jh9b.js → chunk-9nmvm20t.js} +2 -2
- package/dist/{chunk-0fm6jh9b.js.map → chunk-9nmvm20t.js.map} +1 -1
- package/dist/{chunk-98a3k7bp.js → chunk-9xpa7dpy.js} +2 -2
- package/dist/{chunk-98a3k7bp.js.map → chunk-9xpa7dpy.js.map} +1 -1
- package/dist/{chunk-qva4841r.js → chunk-a1exbqcq.js} +3 -3
- package/dist/{chunk-qva4841r.js.map → chunk-a1exbqcq.js.map} +1 -1
- package/dist/{chunk-cw9y6k15.js → chunk-bb19bwg6.js} +2 -2
- package/dist/{chunk-cw9y6k15.js.map → chunk-bb19bwg6.js.map} +1 -1
- package/dist/{chunk-3gvjn3q4.js → chunk-cf7bvd12.js} +1 -1
- package/dist/{chunk-rkbv3df7.js → chunk-djp2xeqe.js} +2 -2
- package/dist/{chunk-rkbv3df7.js.map → chunk-djp2xeqe.js.map} +1 -1
- package/dist/chunk-ds44bqr9.js +4 -0
- package/dist/{chunk-4mcyyh1v.js.map → chunk-ds44bqr9.js.map} +4 -9
- package/dist/{chunk-wzvs3sym.js → chunk-exndjhza.js} +3 -3
- package/dist/{chunk-wzvs3sym.js.map → chunk-exndjhza.js.map} +1 -1
- package/dist/{chunk-f6dd4gd8.js → chunk-f233yzxf.js} +2 -2
- package/dist/{chunk-f6dd4gd8.js.map → chunk-f233yzxf.js.map} +1 -1
- package/dist/chunk-fz5g2z6h.js +4 -0
- package/dist/{chunk-fbvvqf9b.js.map → chunk-fz5g2z6h.js.map} +2 -2
- package/dist/{chunk-vj9538yn.js → chunk-gcszdwcb.js} +2 -2
- package/dist/{chunk-vj9538yn.js.map → chunk-gcszdwcb.js.map} +1 -1
- package/dist/{chunk-pkjq9833.js → chunk-htesx7ym.js} +4 -4
- package/dist/{chunk-pkjq9833.js.map → chunk-htesx7ym.js.map} +1 -1
- package/dist/chunk-hyxmmj9b.js +5 -0
- package/dist/{chunk-n412aa9s.js.map → chunk-hyxmmj9b.js.map} +2 -2
- package/dist/{chunk-stq96kya.js → chunk-k2sjvt0c.js} +2 -2
- package/dist/{chunk-stq96kya.js.map → chunk-k2sjvt0c.js.map} +1 -1
- package/dist/{chunk-zhbrkpb3.js → chunk-k75phgj4.js} +4 -4
- package/dist/{chunk-zhbrkpb3.js.map → chunk-k75phgj4.js.map} +1 -1
- package/dist/{chunk-y64j80v9.js → chunk-m0tp7zjp.js} +2 -2
- package/dist/{chunk-y64j80v9.js.map → chunk-m0tp7zjp.js.map} +1 -1
- package/dist/{chunk-06j6rsew.js → chunk-m45j7p1y.js} +2 -2
- package/dist/{chunk-06j6rsew.js.map → chunk-m45j7p1y.js.map} +1 -1
- package/dist/chunk-mca9wsvs.js +5 -0
- package/dist/{chunk-z2tcxwyr.js.map → chunk-mca9wsvs.js.map} +3 -4
- package/dist/{chunk-tey1xayb.js → chunk-ms13evzp.js} +2 -2
- package/dist/{chunk-tey1xayb.js.map → chunk-ms13evzp.js.map} +1 -1
- package/dist/{chunk-bn1v4sfs.js → chunk-r962ae93.js} +2 -2
- package/dist/{chunk-bn1v4sfs.js.map → chunk-r962ae93.js.map} +1 -1
- package/dist/{chunk-23h0dmx2.js → chunk-s41ees18.js} +2 -2
- package/dist/{chunk-23h0dmx2.js.map → chunk-s41ees18.js.map} +1 -1
- package/dist/chunk-snb68dgr.js +4 -0
- package/dist/{chunk-hwhw98hc.js.map → chunk-snb68dgr.js.map} +1 -1
- package/dist/chunk-sz051605.js +5 -0
- package/dist/chunk-sz051605.js.map +14 -0
- package/dist/{chunk-2cwcfwg3.js → chunk-tr3cbx8k.js} +2 -2
- package/dist/{chunk-2cwcfwg3.js.map → chunk-tr3cbx8k.js.map} +2 -2
- package/dist/{chunk-dgasxgsm.js → chunk-vqcswg7h.js} +2 -2
- package/dist/{chunk-dgasxgsm.js.map → chunk-vqcswg7h.js.map} +2 -2
- package/dist/{chunk-zqsfanvk.js → chunk-wpb1xpdp.js} +2 -2
- package/dist/{chunk-zqsfanvk.js.map → chunk-wpb1xpdp.js.map} +1 -1
- package/dist/{chunk-z1e55w67.js → chunk-ybqss0jy.js} +2 -2
- package/dist/{chunk-z1e55w67.js.map → chunk-ybqss0jy.js.map} +1 -1
- package/dist/{chunk-cejf873g.js → chunk-yk5wqmyh.js} +2 -2
- package/dist/{chunk-cejf873g.js.map → chunk-yk5wqmyh.js.map} +1 -1
- package/dist/{chunk-8kj3zrm9.js → chunk-ywntv8yw.js} +4 -4
- package/dist/{chunk-8kj3zrm9.js.map → chunk-ywntv8yw.js.map} +1 -1
- package/dist/chunks/{ThemeProvider-ByU4BQdL.js → ThemeProvider-BZ2SsSZ3.js} +60 -39
- package/dist/chunks/ThemeProvider-BZ2SsSZ3.js.map +1 -0
- package/dist/chunks/useParams-BN3XXfmG.js +20 -0
- package/dist/chunks/useParams-BN3XXfmG.js.map +1 -0
- package/dist/client/index.js +3 -3
- package/dist/client/index.js.map +1 -1
- package/dist/client/useDictionary.d.ts.map +1 -1
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +2 -2
- package/dist/config/index.js.map +3 -3
- package/dist/database/index.js +1 -1
- package/dist/facades/index.js +2 -2
- package/dist/facades/index.js.map +1 -1
- package/dist/http/ApiRouter.d.ts +30 -2
- package/dist/http/ApiRouter.d.ts.map +1 -1
- package/dist/http/index.js +2 -2
- package/dist/http/index.js.map +1 -1
- package/dist/i18n/defineDictionary.d.ts +7 -4
- package/dist/i18n/defineDictionary.d.ts.map +1 -1
- package/dist/i18n/dictionaryRegistry.d.ts +38 -14
- package/dist/i18n/dictionaryRegistry.d.ts.map +1 -1
- package/dist/i18n/dictionaryRuntime.js +1 -1
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/index.js.map +2 -2
- package/dist/kernel/index.js +2 -2
- package/dist/kernel/index.js.map +2 -2
- package/dist/orm/index.js +2 -2
- package/dist/orm/index.js.map +2 -2
- package/dist/server/index.js +1 -1
- package/dist/services/index.js +2 -2
- package/dist/services/index.js.map +2 -2
- package/dist/testing/index.js +2 -1
- package/dist/testing/index.js.map +1 -1
- package/package.json +5 -2
- package/skills/gemi-react-best-practices/SKILL.md +231 -0
- package/skills/gemi-react-best-practices/rules/_sections.md +56 -0
- package/skills/gemi-react-best-practices/rules/_template.md +28 -0
- package/skills/gemi-react-best-practices/rules/bundle-deep-imports.md +48 -0
- package/skills/gemi-react-best-practices/rules/bundle-mount-gate-heavy-panels.md +63 -0
- package/skills/gemi-react-best-practices/rules/client-form-vs-mutation-hooks.md +57 -0
- package/skills/gemi-react-best-practices/rules/client-loading-error-exports.md +54 -0
- package/skills/gemi-react-best-practices/rules/client-no-effect-data-flow.md +68 -0
- package/skills/gemi-react-best-practices/rules/client-typed-links.md +51 -0
- package/skills/gemi-react-best-practices/rules/controller-authorize-every-tenant-read.md +65 -0
- package/skills/gemi-react-best-practices/rules/controller-parse-request-at-the-boundary.md +54 -0
- package/skills/gemi-react-best-practices/rules/controller-redirect-facade-throws.md +68 -0
- package/skills/gemi-react-best-practices/rules/controller-request-schema.md +61 -0
- package/skills/gemi-react-best-practices/rules/controller-throw-framework-errors.md +57 -0
- package/skills/gemi-react-best-practices/rules/i18n-define-dictionary-inline.md +58 -0
- package/skills/gemi-react-best-practices/rules/orm-analytics-connection.md +53 -0
- package/skills/gemi-react-best-practices/rules/orm-include-not-n-plus-one.md +56 -0
- package/skills/gemi-react-best-practices/rules/orm-paginate-helper.md +69 -0
- package/skills/gemi-react-best-practices/rules/orm-plain-rows-by-default.md +55 -0
- package/skills/gemi-react-best-practices/rules/orm-select-narrow.md +58 -0
- package/skills/gemi-react-best-practices/rules/orm-transaction-no-io.md +54 -0
- package/skills/gemi-react-best-practices/rules/orm-transaction-sequential.md +64 -0
- package/skills/gemi-react-best-practices/rules/payload-dont-overprefetch.md +54 -0
- package/skills/gemi-react-best-practices/rules/payload-instant-vs-prefetch.md +58 -0
- package/skills/gemi-react-best-practices/rules/payload-minimal-view-props.md +51 -0
- package/skills/gemi-react-best-practices/rules/payload-parallel-controller-work.md +56 -0
- package/skills/gemi-react-best-practices/rules/payload-prefetch-late-queries.md +58 -0
- package/skills/gemi-react-best-practices/rules/payload-prefetch-mirrors-usequery.md +52 -0
- package/skills/gemi-react-best-practices/rules/query-debounce-search-variant.md +52 -0
- package/skills/gemi-react-best-practices/rules/query-keep-previous-data.md +40 -0
- package/skills/gemi-react-best-practices/rules/query-lazy-vs-mount-gate.md +54 -0
- package/skills/gemi-react-best-practices/rules/query-mutate-over-refetch.md +55 -0
- package/skills/gemi-react-best-practices/rules/query-no-hand-rolled-fetch.md +60 -0
- package/skills/gemi-react-best-practices/rules/query-revalidate-on-focus.md +44 -0
- package/skills/gemi-react-best-practices/rules/query-share-cache-key.md +51 -0
- package/skills/gemi-react-best-practices/rules/query-suspense-default.md +52 -0
- package/skills/gemi-react-best-practices/rules/routing-cache-policy-constants.md +53 -0
- package/skills/gemi-react-best-practices/rules/routing-middleware-dsl.md +60 -0
- package/skills/gemi-react-best-practices/rules/routing-resource-routes.md +59 -0
- package/skills/gemi-react-best-practices/rules/routing-routers-are-classes.md +55 -0
- package/skills/gemi-react-best-practices/rules/service-lazy-not-module-scope.md +63 -0
- package/skills/gemi-react-best-practices/rules/service-queue-is-in-memory.md +52 -0
- package/skills/gemi-react-best-practices/rules/service-static-token-and-name.md +52 -0
- package/skills/gemi-react-best-practices/rules/structure-discovered-vs-registered.md +71 -0
- package/skills/gemi-react-best-practices/rules/structure-do-not-reinvent-the-framework.md +58 -0
- package/skills/gemi-react-best-practices/rules/testing-assert-behaviour-over-markup.md +54 -0
- package/skills/gemi-react-best-practices/rules/testing-match-the-suite.md +57 -0
- package/skills/gemi-react-best-practices/rules/testing-page-seeds-real-inputs.md +65 -0
- package/dist/chunk-2khdxyjb.js.map +0 -10
- package/dist/chunk-4mcyyh1v.js +0 -4
- package/dist/chunk-fbvvqf9b.js +0 -4
- package/dist/chunk-hwhw98hc.js +0 -4
- package/dist/chunk-n412aa9s.js +0 -5
- package/dist/chunk-q0y0j3ne.js +0 -5
- package/dist/chunk-q0y0j3ne.js.map +0 -11
- package/dist/chunk-txhcx69q.js +0 -6
- package/dist/chunk-z2tcxwyr.js +0 -5
- package/dist/chunks/ThemeProvider-ByU4BQdL.js.map +0 -1
- /package/dist/{chunk-3gvjn3q4.js.map → chunk-cf7bvd12.js.map} +0 -0
|
@@ -1,8 +1,277 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { HttpRequest } from "../http";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { Controller } from "../http/Controller";
|
|
2
|
+
import { HttpRequest } from "../http/HttpRequest";
|
|
3
|
+
import type { MiddlewareInput } from "../http/middlewareList";
|
|
4
|
+
import type { AgentRun, AgentRunResult, AnyAgent, ToolShapesOf } from "./Agent";
|
|
5
|
+
import { FrameCursorEvictedError, liveRuns as defaultLiveRuns, LiveRunNotFoundError, MemoryLiveRuns } from "./store/LiveRuns";
|
|
6
|
+
import { defaultAgentStore, MemoryAgentStore } from "./store/MemoryAgentStore";
|
|
7
|
+
import type { AgentError, AgentMessage, PendingToolCall, ToolShapes } from "./types";
|
|
8
|
+
/**
|
|
9
|
+
* Where conversations live.
|
|
10
|
+
*
|
|
11
|
+
* Stateless is the default and nothing here is required to hold a conversation:
|
|
12
|
+
* the client can carry its own history, and a pending approval travels in it
|
|
13
|
+
* safely because the server signed it. What a store buys is a conversation that
|
|
14
|
+
* survives the browser — and, with `/attach`, one whose interrupted turn is
|
|
15
|
+
* still there after a refresh.
|
|
16
|
+
*/
|
|
17
|
+
export interface AgentStore {
|
|
18
|
+
/**
|
|
19
|
+
* Where a `threadId` comes from. `ApiRouter.agent()` mounts no route for
|
|
20
|
+
* this: the app writes one, calls it here, and hands the id to `useChat` —
|
|
21
|
+
* the mount is the app's because it is where ownership gets recorded, and a
|
|
22
|
+
* store that holds no user cannot do that for it. An id that did not come out
|
|
23
|
+
* of here is `null` from `loadThread` and a 404 from the controller, unless
|
|
24
|
+
* the store's ids are the client's by design (`MemoryAgentStore`'s
|
|
25
|
+
* `clientOwnedIds`).
|
|
26
|
+
*/
|
|
27
|
+
createThread(params: {
|
|
28
|
+
userId?: string | number;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
threadId: string;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* The history, or `null` for a thread the store does not have.
|
|
34
|
+
*
|
|
35
|
+
* `null` and `[]` are different answers and the controller acts on the
|
|
36
|
+
* difference: an empty array is a conversation with nothing in it yet, and a
|
|
37
|
+
* turn on it runs; `null` is a 404 before anything runs. A store that answers
|
|
38
|
+
* `[]` for an id it has never seen turns an expired or mistyped thread into a
|
|
39
|
+
* fresh conversation with no signal, and persists the next turn under the
|
|
40
|
+
* dead id. Only a store whose ids are minted by the client should do that,
|
|
41
|
+
* and then on purpose — see `MemoryAgentStore`'s `clientOwnedIds`.
|
|
42
|
+
*/
|
|
43
|
+
loadThread(threadId: string): Promise<AgentMessage[] | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Upsert by message id: replace a message the thread already holds, append
|
|
46
|
+
* one it does not, and keep the order the thread had. Called with a thread
|
|
47
|
+
* `loadThread` just found; must not create one.
|
|
48
|
+
*
|
|
49
|
+
* The name says append because that is what almost every call is, but a
|
|
50
|
+
* turn that resolves a pending call reports the earlier assistant message
|
|
51
|
+
* again — same id, now with the result attached — and a store that only
|
|
52
|
+
* appends ends up with both versions. A table keyed by message id has the
|
|
53
|
+
* lookup already but still needs an insert-or-update rather than a plain
|
|
54
|
+
* insert, which would fail on the key; a store that is a list has to look
|
|
55
|
+
* before it pushes.
|
|
56
|
+
*/
|
|
57
|
+
appendMessages(threadId: string, messages: AgentMessage[]): Promise<void>;
|
|
7
58
|
}
|
|
59
|
+
/** The default: conversations last as long as the process. */
|
|
60
|
+
export { defaultAgentStore, MemoryAgentStore };
|
|
61
|
+
/**
|
|
62
|
+
* The runs currently in flight, and their frames.
|
|
63
|
+
*
|
|
64
|
+
* A run outlives the request that started it, so something has to hold it while
|
|
65
|
+
* no one is listening, and hold what it emitted meanwhile so a returning client
|
|
66
|
+
* can catch up rather than start over. That is all this is: a per-process map
|
|
67
|
+
* plus a bounded buffer.
|
|
68
|
+
*
|
|
69
|
+
* Per-process is not an implementation shortcut that a better store fixes — a
|
|
70
|
+
* running generator lives in one process, and a second server cannot attach to
|
|
71
|
+
* it. Reattachment therefore needs the request to land where the run is: one
|
|
72
|
+
* server, sticky routing, or a proxy that forwards by `runId`. Worth saying out
|
|
73
|
+
* loud, because the failure mode behind a round-robin load balancer is a
|
|
74
|
+
* refresh that usually works.
|
|
75
|
+
*
|
|
76
|
+
* This is the read side, which is all `attach` and `stop` need. Registering a
|
|
77
|
+
* run and replaying its buffer are on `MemoryLiveRuns`, the only implementation
|
|
78
|
+
* there can be — see the note there for why a second one would not help.
|
|
79
|
+
*/
|
|
80
|
+
export interface LiveRuns {
|
|
81
|
+
/** What the client asks after a refresh: is anything still going here? */
|
|
82
|
+
find(params: {
|
|
83
|
+
threadId: string;
|
|
84
|
+
}): Promise<{
|
|
85
|
+
runId: string;
|
|
86
|
+
seq: number;
|
|
87
|
+
} | null>;
|
|
88
|
+
get(runId: string): AgentRun | null;
|
|
89
|
+
/** Kept for a short while after `run-end`, so a refresh a second late still
|
|
90
|
+
* sees the tail instead of an empty screen. */
|
|
91
|
+
ttlMs: number;
|
|
92
|
+
}
|
|
93
|
+
export { FrameCursorEvictedError, LiveRunNotFoundError, MemoryLiveRuns, defaultLiveRuns as liveRuns, };
|
|
94
|
+
export type AgentHookContext = {
|
|
95
|
+
req: HttpRequest<any, any>;
|
|
96
|
+
runId: string;
|
|
97
|
+
threadId?: string;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* `Controller.kind` is typed as the literal `"controller"`, so a subclass that
|
|
101
|
+
* declares a `kind` of its own fails the static-side check (TS2417). Widening
|
|
102
|
+
* it belongs in `http/Controller.ts`, which this slice does not own; erasing
|
|
103
|
+
* the static side of the base here is the smaller change and costs nothing —
|
|
104
|
+
* `Controller.kind` has no reader, in this package or out of it.
|
|
105
|
+
*/
|
|
106
|
+
declare const ControllerBase: new () => Controller;
|
|
107
|
+
export declare abstract class AgentController<A extends AnyAgent = AnyAgent> extends ControllerBase {
|
|
108
|
+
static kind: "agent-controller";
|
|
109
|
+
/** The agent this controller serves. A property rather than a constructor
|
|
110
|
+
* argument so `Router.agent(ChatController)` can take the class, matching how
|
|
111
|
+
* every other controller is mounted. */
|
|
112
|
+
abstract agent: A;
|
|
113
|
+
/**
|
|
114
|
+
* Defaults to the process-wide `MemoryAgentStore`.
|
|
115
|
+
*
|
|
116
|
+
* Whatever you put here, make it something that outlives the request: this
|
|
117
|
+
* controller is constructed fresh for every call, so `store = new
|
|
118
|
+
* MemoryAgentStore()` written here is an empty store on every turn and a
|
|
119
|
+
* threaded conversation silently reads back nothing. Assign a module-level
|
|
120
|
+
* instance, or a store whose state is somewhere else entirely.
|
|
121
|
+
*/
|
|
122
|
+
store: AgentStore;
|
|
123
|
+
/**
|
|
124
|
+
* Defaults to the process-wide map. Overridable so a test — or an app running
|
|
125
|
+
* two agents that must not see each other's runs — can hold its own; not so
|
|
126
|
+
* that it can be moved off the process, which is not a thing that can be
|
|
127
|
+
* done. See `MemoryLiveRuns`.
|
|
128
|
+
*/
|
|
129
|
+
liveRuns: MemoryLiveRuns;
|
|
130
|
+
/** Appended to the agent's static instructions for this request — the user's
|
|
131
|
+
* name, tenant, today's date. */
|
|
132
|
+
instructions(req: HttpRequest<any, any>): string | Promise<string> | void;
|
|
133
|
+
/**
|
|
134
|
+
* `POST /<path>` — one route for every client turn. A first message, an
|
|
135
|
+
* approval, an answer to a question and a client tool's result are all just
|
|
136
|
+
* the next turn, so none of them gets an endpoint of its own.
|
|
137
|
+
*/
|
|
138
|
+
stream(req?: HttpRequest<any, any>): Promise<Response>;
|
|
139
|
+
/**
|
|
140
|
+
* A thread holds one run at a time; a new turn on it ends the old one first.
|
|
141
|
+
*
|
|
142
|
+
* Since a dropped connection no longer stops a run, a user who sends again
|
|
143
|
+
* mid-answer used to leave the first run going. It could not see the new
|
|
144
|
+
* turn, the new run's `loadThread` could not see its answer, and both
|
|
145
|
+
* appended when they finished — in whichever order the model returned them,
|
|
146
|
+
* so the thread read `user2, assistant2, user1, assistant1`. `byThread` then
|
|
147
|
+
* named the second run while the first was still live and unstoppable by
|
|
148
|
+
* `threadId`.
|
|
149
|
+
*
|
|
150
|
+
* Stopping the old run and waiting for its transcript to land is chosen over
|
|
151
|
+
* refusing the new turn with a 409, because sending again *is* the stop: it
|
|
152
|
+
* is what `useChat.send` means, and a client that has to poll `/stop` until
|
|
153
|
+
* the run is really gone before it may post the turn it has already shown is
|
|
154
|
+
* a worse client for no better thread. The cost is that the new turn waits
|
|
155
|
+
* for the old run to unwind, which is as long as its slowest tool in flight —
|
|
156
|
+
* and that wait is the thing that puts `assistant1` before `user2`.
|
|
157
|
+
*
|
|
158
|
+
* The wait is on `persistRun`, not on `run.result()`. `result()` settling is
|
|
159
|
+
* the transcript being final, not stored: `appendMessages` runs after it, and
|
|
160
|
+
* a `loadThread` in that gap reads a history the old answer is missing from,
|
|
161
|
+
* which is the original bug by a shorter route. It is also *only* that:
|
|
162
|
+
* `persistRun` settles once the transcript is stored and lets the app's
|
|
163
|
+
* hooks run on without it, so a slow `onMessage` is not a slow thread and a
|
|
164
|
+
* hung one is not a hung thread.
|
|
165
|
+
*
|
|
166
|
+
* The lock around it is what makes a *third* turn wait for the second rather
|
|
167
|
+
* than for the first. Two turns arriving together both see the same live
|
|
168
|
+
* run, both stop it, both wait for it, and both start — the same race, one
|
|
169
|
+
* message later. Under the lock the later one finds the earlier one
|
|
170
|
+
* registered and stops that instead. Per process, like `LiveRuns`, and for
|
|
171
|
+
* the same reason: the run it guards lives here.
|
|
172
|
+
*/
|
|
173
|
+
private withThread;
|
|
174
|
+
/**
|
|
175
|
+
* `POST /<path>/attach` — subscribe to a run already in progress, from a
|
|
176
|
+
* cursor. This is a read of a live run, not a continuation of a stopped one:
|
|
177
|
+
* the work never paused, the listener changed.
|
|
178
|
+
*
|
|
179
|
+
* The cursor is `from`, else the client's `cursor`, else `Last-Event-ID`,
|
|
180
|
+
* else the oldest frame still buffered — and it is honoured only for the run
|
|
181
|
+
* the client's `runId` names. A cursor the buffer has dropped is a 410 naming
|
|
182
|
+
* what survives; *no* cursor is the tail, because a page reattaching on mount
|
|
183
|
+
* has no transcript to leave a hole in. See `resolveCursor`.
|
|
184
|
+
*/
|
|
185
|
+
attach(req?: HttpRequest<any, any>): Promise<Response>;
|
|
186
|
+
/**
|
|
187
|
+
* `POST /<path>/stop` — the explicit cancel. Since a dropped connection no
|
|
188
|
+
* longer stops a run, this and a later turn on the same thread are the only
|
|
189
|
+
* things that do, and it is why stopping cannot be a client-side concern:
|
|
190
|
+
* the tool loop is here, and a client that stops reading has not stopped
|
|
191
|
+
* step four from charging a card.
|
|
192
|
+
*
|
|
193
|
+
* Returns as soon as the run is aborted, not when it has finished unwinding.
|
|
194
|
+
* The terminal events — the stopped tool results, the aborted message — go
|
|
195
|
+
* out on the run's own stream, so whoever is watching it sees the ending,
|
|
196
|
+
* and `onMessage` records it whether anyone is watching or not.
|
|
197
|
+
*
|
|
198
|
+
* Answers `{ stopped }` normally, and a `Response` only to reject a request
|
|
199
|
+
* it could not read — the union is the error, not a second success shape.
|
|
200
|
+
*/
|
|
201
|
+
stop(req?: HttpRequest<any, any>): Promise<{
|
|
202
|
+
stopped: boolean;
|
|
203
|
+
} | Response>;
|
|
204
|
+
/** `POST /<path>/files` — uploads an attachment and returns its file id. */
|
|
205
|
+
upload(req?: HttpRequest<any, any>): Promise<{
|
|
206
|
+
fileId: string;
|
|
207
|
+
}>;
|
|
208
|
+
/**
|
|
209
|
+
* Protected, not private: these exist to be overridden. `onMessage` fires for
|
|
210
|
+
* every completed message, user and assistant alike, and is the intended
|
|
211
|
+
* persistence point for an app that is not using `store`.
|
|
212
|
+
*/
|
|
213
|
+
protected onMessage(message: AgentMessage, ctx: AgentHookContext): void | Promise<void>;
|
|
214
|
+
protected onToolCall(call: {
|
|
215
|
+
toolCallId: string;
|
|
216
|
+
name: string;
|
|
217
|
+
input: unknown;
|
|
218
|
+
}, ctx: AgentHookContext): void | Promise<void>;
|
|
219
|
+
/** Fires before the stream ends `awaiting-input` — where to notify whoever
|
|
220
|
+
* has to approve, if they are not the person watching the stream. */
|
|
221
|
+
protected onAwaitingInput(pending: PendingToolCall[], ctx: AgentHookContext): void | Promise<void>;
|
|
222
|
+
protected onError(error: AgentError, ctx: AgentHookContext): void | Promise<void>;
|
|
223
|
+
protected onStreamComplete(result: AgentRunResult<ToolShapesOf<A["tools"]>, any>, ctx: AgentHookContext): void | Promise<void>;
|
|
224
|
+
/**
|
|
225
|
+
* WHAT HAPPENS WHEN A HOOK THROWS: it is reported and the run carries on.
|
|
226
|
+
*
|
|
227
|
+
* The alternative is to fail the run, and that trade is not close. These
|
|
228
|
+
* hooks are an app's persistence and notification points; the run is a model
|
|
229
|
+
* call the user has already been charged for and whose tools may already have
|
|
230
|
+
* charged a card. Letting a failed `INSERT` in `onMessage` abort a generation
|
|
231
|
+
* mid-sentence loses the answer as well as the row, and the user cannot
|
|
232
|
+
* retry into a better outcome. So the answer survives and the failure is
|
|
233
|
+
* logged.
|
|
234
|
+
*
|
|
235
|
+
* It is logged rather than routed to `onError`: `onError` is itself a hook,
|
|
236
|
+
* and a hook that throws inside the handler for hooks that throw is a loop.
|
|
237
|
+
* Override this to send it somewhere with a pager attached.
|
|
238
|
+
*/
|
|
239
|
+
protected reportHookFailure(error: unknown): void;
|
|
240
|
+
private dispatchEvent;
|
|
241
|
+
/**
|
|
242
|
+
* Runs after the stream is over, whether or not anyone was still watching it.
|
|
243
|
+
*
|
|
244
|
+
* The messages come from `result()` rather than from the event stream because
|
|
245
|
+
* assembling a message out of deltas is the agent's job and doing it twice is
|
|
246
|
+
* how the two copies drift. It also means a stopped run persists the same way
|
|
247
|
+
* a finished one does: `stop()` finalizes the transcript, so by the time this
|
|
248
|
+
* resolves there is a valid history to store.
|
|
249
|
+
*
|
|
250
|
+
* Settles when the transcript is in the store, not when the app is done with
|
|
251
|
+
* it. The next turn on this thread waits on this (see `withThread`), and the
|
|
252
|
+
* hooks are the app's: an `onMessage` that writes to something slow would
|
|
253
|
+
* make every later turn wait for it, once per message of the old run, and
|
|
254
|
+
* one that never settles — which `safely` cannot catch — would hold the
|
|
255
|
+
* thread, and every turn queued on it, behind an open connection each. So
|
|
256
|
+
* the hooks run on after this on their own, reported the same way.
|
|
257
|
+
*/
|
|
258
|
+
private persistRun;
|
|
259
|
+
/** The hooks on a finished run, in order. Never rejects: see `safely`. */
|
|
260
|
+
private notifyRun;
|
|
261
|
+
private safely;
|
|
262
|
+
}
|
|
263
|
+
export type AgentRouteMethod = "stream" | "attach" | "stop" | "upload";
|
|
264
|
+
export type AgentMiddlewareConfig = Partial<Record<AgentRouteMethod, MiddlewareInput>>;
|
|
265
|
+
export type AgentRoute<T extends new () => AgentController<any>> = {
|
|
266
|
+
__internal_brand: "AgentRoute";
|
|
267
|
+
controller: T;
|
|
268
|
+
middleware(config: AgentMiddlewareConfig): AgentRoute<T>;
|
|
269
|
+
};
|
|
270
|
+
/** What `CreateRPC` should produce for an agent route: enough for the client to
|
|
271
|
+
* type its messages, and nothing that drags server code into the bundle. */
|
|
272
|
+
export type AgentRouteRPC<T extends new () => AgentController<any>> = {
|
|
273
|
+
__agent: true;
|
|
274
|
+
tools: InstanceType<T>["agent"] extends AnyAgent ? ToolShapesOf<InstanceType<T>["agent"]["tools"]> : ToolShapes;
|
|
275
|
+
output: unknown;
|
|
276
|
+
};
|
|
8
277
|
//# sourceMappingURL=AgentController.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentController.d.ts","sourceRoot":"","sources":["../../ai/AgentController.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"AgentController.d.ts","sourceRoot":"","sources":["../../ai/AgentController.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import type { ReasoningEffort } from "./Agent";
|
|
2
|
+
import { type ResponsesEndpoint } from "./providers/call";
|
|
3
|
+
import type { JSONSchema } from "./Schema";
|
|
4
|
+
import type { AgentError, AgentMessage, FinishReason, Usage } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* A provider makes one model call. It does not run the tool loop.
|
|
7
|
+
*
|
|
8
|
+
* The split matters: approvals, `maxSteps`, deferred tools, skill loading and
|
|
9
|
+
* persistence are all provider-independent, and putting them in the provider
|
|
10
|
+
* would mean writing them again for the second provider. So the provider's
|
|
11
|
+
* whole job is to translate gemi's messages into a request, and the response
|
|
12
|
+
* stream back into `ProviderEvent`s. Everything above that lives in `Agent`.
|
|
13
|
+
*
|
|
14
|
+
* v1 targets OpenAI's Responses API — native reasoning items and strict
|
|
15
|
+
* structured output without reassembling them by hand. The interface is kept
|
|
16
|
+
* free of anything Responses-specific so a Chat Completions provider (for older
|
|
17
|
+
* Azure deployments and OpenAI-compatible gateways) can be added later without
|
|
18
|
+
* touching Agent, Controller or the client.
|
|
19
|
+
*/
|
|
20
|
+
/** What a provider will actually honour, so `Agent` can drop the rest rather
|
|
21
|
+
* than have a request rejected at runtime. */
|
|
22
|
+
export type ProviderCapabilities = {
|
|
23
|
+
reasoning: boolean;
|
|
24
|
+
structuredOutput: boolean;
|
|
25
|
+
fileInput: boolean;
|
|
26
|
+
parallelToolCalls: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Tool search, and with it deferred loading. Only recent models have it, so a
|
|
29
|
+
* provider that answers `false` is sent every schema inline and the agent
|
|
30
|
+
* runs identically — deferral is a token optimization, and an optimization
|
|
31
|
+
* that changed behaviour when unavailable would not be one.
|
|
32
|
+
*/
|
|
33
|
+
toolSearch: boolean;
|
|
34
|
+
};
|
|
35
|
+
/** A tool as the model is shown it: schema only, no implementation. */
|
|
36
|
+
export type ProviderToolSpec = {
|
|
37
|
+
name: string;
|
|
38
|
+
description: string;
|
|
39
|
+
parameters: JSONSchema;
|
|
40
|
+
strict: boolean;
|
|
41
|
+
/** `defer_loading`: send the name and description, withhold the schema until
|
|
42
|
+
* the model searches for it. Ignored when `capabilities.toolSearch` is
|
|
43
|
+
* false. */
|
|
44
|
+
deferred?: boolean;
|
|
45
|
+
};
|
|
46
|
+
/** Tools grouped for search. Flattened back to a list by a provider without
|
|
47
|
+
* tool search, since the grouping exists to be searched. */
|
|
48
|
+
export type ProviderToolNamespace = {
|
|
49
|
+
name: string;
|
|
50
|
+
description: string;
|
|
51
|
+
tools: ProviderToolSpec[];
|
|
52
|
+
};
|
|
53
|
+
export interface ProviderStreamParams {
|
|
54
|
+
messages: AgentMessage[];
|
|
55
|
+
systemPrompt?: string;
|
|
56
|
+
tools?: (ProviderToolSpec | ProviderToolNamespace)[];
|
|
57
|
+
/** Set when the agent declares an `output` schema; the provider turns it into
|
|
58
|
+
* whatever its own strict-JSON parameter is. */
|
|
59
|
+
output?: {
|
|
60
|
+
name: string;
|
|
61
|
+
schema: JSONSchema;
|
|
62
|
+
};
|
|
63
|
+
/** Optional: silently dropped by a provider whose `capabilities.reasoning`
|
|
64
|
+
* is false, since a model that cannot reason should not fail a request. */
|
|
65
|
+
reasoning?: ReasoningEffort;
|
|
66
|
+
temperature?: number;
|
|
67
|
+
maxOutputTokens?: number;
|
|
68
|
+
signal?: AbortSignal;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The events of a single model call. Deliberately smaller than
|
|
72
|
+
* `AgentStreamEvent`: no run, message, tool-result or approval events, because
|
|
73
|
+
* a provider knows about none of those.
|
|
74
|
+
*/
|
|
75
|
+
export type ProviderEvent = {
|
|
76
|
+
type: "text-delta";
|
|
77
|
+
delta: string;
|
|
78
|
+
} | {
|
|
79
|
+
type: "reasoning-delta";
|
|
80
|
+
delta: string;
|
|
81
|
+
id?: string;
|
|
82
|
+
}
|
|
83
|
+
/** Arguments arrive as JSON fragments; the provider passes them through and
|
|
84
|
+
* `Agent` assembles and validates against the tool's schema. */
|
|
85
|
+
| {
|
|
86
|
+
type: "tool-call-delta";
|
|
87
|
+
toolCallId: string;
|
|
88
|
+
name: string;
|
|
89
|
+
argsDelta: string;
|
|
90
|
+
namespace?: string;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* `name` IS FLAT AND STAYS FLAT. This was an open question and the API has
|
|
94
|
+
* answered it: a call to a function that lives inside a namespace comes back
|
|
95
|
+
* as `{name: "getOrder", namespace: "crm"}`, not as `"crm.getOrder"` —
|
|
96
|
+
* recorded in `providers/__fixtures__/openai-tool-search.sse` and pinned by
|
|
97
|
+
* a test that reads that file. So `name` is already the key `Agent`'s tool
|
|
98
|
+
* registry is built on, which is what makes tool names having to be globally
|
|
99
|
+
* unique within an agent (see `ToolNamespace`) the right rule rather than an
|
|
100
|
+
* inconvenience.
|
|
101
|
+
*
|
|
102
|
+
* `namespace` is carried beside it, absent for a tool that was listed bare.
|
|
103
|
+
* It is provenance, not identity: it says which group the model chose to
|
|
104
|
+
* look in, which is worth recording next to the call and is worthless for
|
|
105
|
+
* finding the tool. Folding it into `name` would make a name that is
|
|
106
|
+
* sometimes qualified and sometimes not, and nothing could match on that.
|
|
107
|
+
*/
|
|
108
|
+
| {
|
|
109
|
+
type: "tool-call";
|
|
110
|
+
toolCallId: string;
|
|
111
|
+
name: string;
|
|
112
|
+
args: string;
|
|
113
|
+
namespace?: string;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The model went looking for a deferred tool and pulled its schema in. Worth
|
|
117
|
+
* surfacing rather than swallowing: it is a step the user paid for, and the
|
|
118
|
+
* pause before it is otherwise unexplained.
|
|
119
|
+
*
|
|
120
|
+
* TWO FIELDS, not one. `loaded` is the function names — `["listOrders",
|
|
121
|
+
* "getOrder"]` — and `namespaces` is the groups they came out of —
|
|
122
|
+
* `["crm"]`. Search results arrive as a tree of namespaces containing
|
|
123
|
+
* functions, so a single flat list has to pick one level and throw the other
|
|
124
|
+
* away, and both levels are worth saying: "searched crm, loaded getOrder"
|
|
125
|
+
* reads better than either half, and the group is the thing the model
|
|
126
|
+
* actually chose between.
|
|
127
|
+
*
|
|
128
|
+
* `namespaces` is required rather than optional because the parser always
|
|
129
|
+
* knows the answer, and an optional field would let a future provider forget
|
|
130
|
+
* to fill it in silently. Empty means the search returned bare functions.
|
|
131
|
+
*/
|
|
132
|
+
| {
|
|
133
|
+
type: "tool-search";
|
|
134
|
+
loaded: string[];
|
|
135
|
+
namespaces: string[];
|
|
136
|
+
} | {
|
|
137
|
+
type: "output-delta";
|
|
138
|
+
delta: string;
|
|
139
|
+
} | {
|
|
140
|
+
type: "finish";
|
|
141
|
+
reason: FinishReason;
|
|
142
|
+
usage: Usage;
|
|
143
|
+
} | {
|
|
144
|
+
type: "error";
|
|
145
|
+
error: AgentError;
|
|
146
|
+
};
|
|
147
|
+
export type ProviderStream = AsyncIterable<ProviderEvent>;
|
|
148
|
+
export type ProviderConfig = {
|
|
149
|
+
apiKey?: string;
|
|
150
|
+
baseURL?: string;
|
|
151
|
+
timeoutMs?: number;
|
|
152
|
+
maxRetries?: number;
|
|
153
|
+
headers?: Record<string, string>;
|
|
154
|
+
};
|
|
155
|
+
export declare abstract class AgentProvider {
|
|
156
|
+
abstract readonly model: string;
|
|
157
|
+
abstract readonly capabilities: ProviderCapabilities;
|
|
158
|
+
/** The model ids this provider knows about — for autocomplete only; any
|
|
159
|
+
* string is still accepted, because a new model must not require a gemi
|
|
160
|
+
* release to use. */
|
|
161
|
+
static models(): readonly string[];
|
|
162
|
+
abstract stream(params: ProviderStreamParams): ProviderStream;
|
|
163
|
+
/**
|
|
164
|
+
* Uploads a file and returns the id a `FilePart` carries. Message history
|
|
165
|
+
* therefore holds provider file ids, which is the trade for getting vision
|
|
166
|
+
* and PDF input without gemi owning a storage story in v1.
|
|
167
|
+
*/
|
|
168
|
+
abstract upload(file: File): Promise<string>;
|
|
169
|
+
/**
|
|
170
|
+
* Maps a provider's error body onto the normalized codes, so an app can
|
|
171
|
+
* branch on `rate_limited` without knowing whose rate limit it was.
|
|
172
|
+
*
|
|
173
|
+
* Shared rather than abstract-in-practice: Azure answers the same error
|
|
174
|
+
* envelope as OpenAI, and the one place it differs — the content filter's
|
|
175
|
+
* code, buried in `innererror` — is handled by reading both.
|
|
176
|
+
*/
|
|
177
|
+
normalizeError(error: unknown): AgentError;
|
|
178
|
+
}
|
|
179
|
+
export declare class OpenAIProvider extends AgentProvider {
|
|
180
|
+
readonly model: string;
|
|
181
|
+
readonly capabilities: ProviderCapabilities;
|
|
182
|
+
protected readonly config: ProviderConfig;
|
|
183
|
+
constructor(model: string, config?: ProviderConfig);
|
|
184
|
+
/** Config defaults come from gemi's config (`ai.openai`), so an app that has
|
|
185
|
+
* set `OPENAI_API_KEY` writes only the model name. */
|
|
186
|
+
static model(model: string, config?: ProviderConfig): OpenAIProvider;
|
|
187
|
+
static models(): readonly string[];
|
|
188
|
+
stream(params: ProviderStreamParams): ProviderStream;
|
|
189
|
+
upload(file: File): Promise<string>;
|
|
190
|
+
protected baseURL(): string;
|
|
191
|
+
protected endpoint(): ResponsesEndpoint;
|
|
192
|
+
}
|
|
193
|
+
export type AzureConfig = ProviderConfig & {
|
|
194
|
+
/**
|
|
195
|
+
* The resource host, with or without a trailing `/openai`. Both spellings
|
|
196
|
+
* work — `https://<resource>.cognitiveservices.azure.com` and
|
|
197
|
+
* `https://<resource>.openai.azure.com` — and neither is rewritten, because
|
|
198
|
+
* only one of them exists for a resource that was not created as
|
|
199
|
+
* kind=OpenAI. See `azureBase` for what is done to it.
|
|
200
|
+
*/
|
|
201
|
+
endpoint?: string;
|
|
202
|
+
/**
|
|
203
|
+
* Just the resource name, when there is no endpoint to hand. `<name>` is
|
|
204
|
+
* expanded to `https://<name>.cognitiveservices.azure.com/openai`.
|
|
205
|
+
*/
|
|
206
|
+
resourceName?: string;
|
|
207
|
+
apiVersion?: string;
|
|
208
|
+
/**
|
|
209
|
+
* The deployment to call, when it is not named after the model. Azure lets
|
|
210
|
+
* whoever ran the template call it anything, and plenty of them are called
|
|
211
|
+
* `prod` — this is the override the class comment promises.
|
|
212
|
+
*/
|
|
213
|
+
deployment?: string;
|
|
214
|
+
/**
|
|
215
|
+
* For Entra ID instead of a key. A function, not a token, because these
|
|
216
|
+
* expire mid-conversation.
|
|
217
|
+
*/
|
|
218
|
+
getToken?: () => Promise<string>;
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Its own class rather than a flag on `OpenAIProvider`: Azure names the
|
|
222
|
+
* deployment rather than the model, pins an api-version, authenticates with an
|
|
223
|
+
* `api-key` header or an Entra token, and puts the resource in the host. One
|
|
224
|
+
* class carrying both shapes means every field is conditionally meaningful.
|
|
225
|
+
*
|
|
226
|
+
* (It used to put the deployment in the URL as well. It does not: the Responses
|
|
227
|
+
* API serves no such path — see `azureBase` for the measurements.)
|
|
228
|
+
*
|
|
229
|
+
* The API stays symmetrical — `.model()`, not `.deployment()`. Apps name a
|
|
230
|
+
* model; mapping that onto a deployment is this class's problem, and an app
|
|
231
|
+
* that named its deployment differently overrides it in config.
|
|
232
|
+
*/
|
|
233
|
+
export declare class AzureOpenAIProvider extends AgentProvider {
|
|
234
|
+
readonly model: string;
|
|
235
|
+
readonly capabilities: ProviderCapabilities;
|
|
236
|
+
protected readonly config: AzureConfig;
|
|
237
|
+
constructor(model: string, config?: AzureConfig);
|
|
238
|
+
/** Defaults from gemi's config (`ai.azure`). */
|
|
239
|
+
static model(model: string, config?: AzureConfig): AzureOpenAIProvider;
|
|
240
|
+
static models(): readonly string[];
|
|
241
|
+
stream(params: ProviderStreamParams): ProviderStream;
|
|
242
|
+
upload(file: File): Promise<string>;
|
|
243
|
+
protected deployment(): string;
|
|
244
|
+
/**
|
|
245
|
+
* The resource base, `<host>/openai`, from whichever of the three ways it was
|
|
246
|
+
* configured. A bare resource name expands to the `cognitiveservices` host
|
|
247
|
+
* rather than the `openai.azure.com` one: both answer for a resource created
|
|
248
|
+
* as kind=OpenAI, only `cognitiveservices` answers for an AI Foundry or
|
|
249
|
+
* multi-service resource, so it is the spelling that is right more often. An
|
|
250
|
+
* app on the other one sets `endpoint` and nothing rewrites it.
|
|
251
|
+
*/
|
|
252
|
+
protected base(): string;
|
|
253
|
+
protected endpoint(): ResponsesEndpoint;
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=AgentProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentProvider.d.ts","sourceRoot":"","sources":["../../ai/AgentProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAA+B,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAIvF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAE7E;;;;;;;;;;;;;;GAcG;AAEH;+CAC+C;AAC/C,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,EAAE,OAAO,CAAC;IAC3B;;;;;OAKG;IACH,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,uEAAuE;AACvE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB;;iBAEa;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF;6DAC6D;AAC7D,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,CAAC,gBAAgB,GAAG,qBAAqB,CAAC,EAAE,CAAC;IACrD;qDACiD;IACjD,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC;IAC9C;gFAC4E;IAC5E,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE;AACzD;iEACiE;GAC/D;IACE,IAAI,EAAE,iBAAiB,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AACH;;;;;;;;;;;;;;;GAeG;GACD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE;AAC3F;;;;;;;;;;;;;;;;GAgBG;GACD;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAEzC,MAAM,MAAM,cAAc,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,CAAC;AAaF,8BAAsB,aAAa;IACjC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAErD;;0BAEsB;IACtB,MAAM,CAAC,MAAM,IAAI,SAAS,MAAM,EAAE;IAIlC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,cAAc;IAE7D;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAE5C;;;;;;;OAOG;IACH,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU;CAG3C;AAwCD,qBAAa,cAAe,SAAQ,aAAa;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAC5C,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;gBAE9B,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,cAAmB;IAOtD;2DACuD;IACvD,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc,GAAG,cAAc;IAIpE,MAAM,CAAC,MAAM,IAAI,SAAS,MAAM,EAAE;IAIlC,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,cAAc;IAcpD,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAInC,SAAS,CAAC,OAAO,IAAI,MAAM;IAO3B,SAAS,CAAC,QAAQ,IAAI,iBAAiB;CAiBxC;AAED,MAAM,MAAM,WAAW,GAAG,cAAc,GAAG;IACzC;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAClC,CAAC;AAiEF;;;;;;;;;;;;GAYG;AACH,qBAAa,mBAAoB,SAAQ,aAAa;IACpD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAC5C,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;gBAE3B,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,WAAgB;IAUnD,gDAAgD;IAChD,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,mBAAmB;IAItE,MAAM,CAAC,MAAM,IAAI,SAAS,MAAM,EAAE;IAIlC,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,cAAc;IAcpD,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAInC,SAAS,CAAC,UAAU,IAAI,MAAM;IAI9B;;;;;;;OAOG;IACH,SAAS,CAAC,IAAI,IAAI,MAAM;IASxB,SAAS,CAAC,QAAQ,IAAI,iBAAiB;CA4BxC"}
|