@effect-uai/core 0.13.0 → 0.15.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/{Audio-60lKKHxS.d.mts → Audio-_nGR4V0X.d.mts} +2 -2
- package/dist/{Audio-60lKKHxS.d.mts.map → Audio-_nGR4V0X.d.mts.map} +1 -1
- package/dist/Image-Cv6iBLTy.d.mts +99 -0
- package/dist/Image-Cv6iBLTy.d.mts.map +1 -0
- package/dist/{Items-SfUabNuB.d.mts → Items-C7MyrYPX.d.mts} +35 -4
- package/dist/Items-C7MyrYPX.d.mts.map +1 -0
- package/dist/Media-BbX7BAaO.d.mts +60 -0
- package/dist/Media-BbX7BAaO.d.mts.map +1 -0
- package/dist/MessengerError-CeK6VAcu.d.mts +64 -0
- package/dist/MessengerError-CeK6VAcu.d.mts.map +1 -0
- package/dist/{Tool-DE-rnvkw.d.mts → Tool-BF78QWtn.d.mts} +2 -2
- package/dist/{Tool-DE-rnvkw.d.mts.map → Tool-BF78QWtn.d.mts.map} +1 -1
- package/dist/{ToolEvent-D99MGQYH.d.mts → ToolEvent-Di4a723B.d.mts} +2 -2
- package/dist/{ToolEvent-D99MGQYH.d.mts.map → ToolEvent-Di4a723B.d.mts.map} +1 -1
- package/dist/{ToolResult-Cj8ChodL.d.mts → ToolResult-BsYQRjmW.d.mts} +2 -2
- package/dist/{ToolResult-Cj8ChodL.d.mts.map → ToolResult-BsYQRjmW.d.mts.map} +1 -1
- package/dist/{Toolkit-BEZrNPTI.d.mts → Toolkit-DAjJ9Tvl.d.mts} +5 -5
- package/dist/{Toolkit-BEZrNPTI.d.mts.map → Toolkit-DAjJ9Tvl.d.mts.map} +1 -1
- package/dist/browser/BrowserTool.d.mts +1 -1
- package/dist/capabilities/Capabilities.d.mts +26 -2
- package/dist/capabilities/Capabilities.d.mts.map +1 -1
- package/dist/capabilities/Capabilities.mjs +32 -1
- package/dist/capabilities/Capabilities.mjs.map +1 -1
- package/dist/domain/Audio.d.mts +1 -1
- package/dist/domain/Image.d.mts +3 -2
- package/dist/domain/Image.mjs +29 -3
- package/dist/domain/Image.mjs.map +1 -1
- package/dist/domain/Items.d.mts +2 -2
- package/dist/domain/Items.mjs +19 -1
- package/dist/domain/Items.mjs.map +1 -1
- package/dist/domain/Media.d.mts +2 -2
- package/dist/domain/Media.mjs +51 -2
- package/dist/domain/Media.mjs.map +1 -1
- package/dist/domain/Music.d.mts +3 -8
- package/dist/domain/Music.d.mts.map +1 -1
- package/dist/domain/Music.mjs.map +1 -1
- package/dist/domain/Research.d.mts +1 -1
- package/dist/domain/Turn.d.mts +73 -9
- package/dist/domain/Turn.d.mts.map +1 -1
- package/dist/domain/Turn.mjs +38 -2
- package/dist/domain/Turn.mjs.map +1 -1
- package/dist/embedding-model/Embedding.d.mts +1 -1
- package/dist/image-generator/ImageGenerator.d.mts +188 -0
- package/dist/image-generator/ImageGenerator.d.mts.map +1 -0
- package/dist/image-generator/ImageGenerator.mjs +50 -0
- package/dist/image-generator/ImageGenerator.mjs.map +1 -0
- package/dist/inbox/Inbox.d.mts +16 -0
- package/dist/inbox/Inbox.d.mts.map +1 -0
- package/dist/inbox/Inbox.mjs +28 -0
- package/dist/inbox/Inbox.mjs.map +1 -0
- package/dist/inbox/Inbox.test.d.mts +1 -0
- package/dist/inbox/Inbox.test.mjs +42 -0
- package/dist/inbox/Inbox.test.mjs.map +1 -0
- package/dist/index.d.mts +15 -9
- package/dist/index.mjs +8 -2
- package/dist/language-model/LanguageModel.d.mts +2 -2
- package/dist/messenger/Messenger.d.mts +472 -0
- package/dist/messenger/Messenger.d.mts.map +1 -0
- package/dist/messenger/Messenger.mjs +66 -0
- package/dist/messenger/Messenger.mjs.map +1 -0
- package/dist/messenger/MessengerAdapter.d.mts +35 -0
- package/dist/messenger/MessengerAdapter.d.mts.map +1 -0
- package/dist/messenger/MessengerAdapter.mjs +102 -0
- package/dist/messenger/MessengerAdapter.mjs.map +1 -0
- package/dist/messenger/MessengerAdapter.test.d.mts +1 -0
- package/dist/messenger/MessengerAdapter.test.mjs +138 -0
- package/dist/messenger/MessengerAdapter.test.mjs.map +1 -0
- package/dist/messenger/MessengerError.d.mts +2 -0
- package/dist/messenger/MessengerError.mjs +39 -0
- package/dist/messenger/MessengerError.mjs.map +1 -0
- package/dist/music-generator/MusicGenerator.d.mts +3 -2
- package/dist/music-generator/MusicGenerator.d.mts.map +1 -1
- package/dist/observability/Metrics.d.mts +1 -1
- package/dist/speech-synthesizer/SpeechSynthesizer.d.mts +1 -1
- package/dist/streaming/Multipart.d.mts +21 -0
- package/dist/streaming/Multipart.d.mts.map +1 -0
- package/dist/streaming/Multipart.mjs +26 -0
- package/dist/streaming/Multipart.mjs.map +1 -0
- package/dist/testing/MockMessenger.d.mts +192 -0
- package/dist/testing/MockMessenger.d.mts.map +1 -0
- package/dist/testing/MockMessenger.mjs +76 -0
- package/dist/testing/MockMessenger.mjs.map +1 -0
- package/dist/testing/MockMusicGenerator.d.mts +1 -1
- package/dist/testing/MockProvider.d.mts +1 -1
- package/dist/testing/MockSpeechSynthesizer.d.mts +1 -1
- package/dist/tool/Approval.d.mts +3 -3
- package/dist/tool/HistoryCheck.d.mts +2 -2
- package/dist/tool/Tool.d.mts +1 -1
- package/dist/tool/ToolEvent.d.mts +1 -1
- package/dist/tool/ToolResult.d.mts +1 -1
- package/dist/tool/Toolkit.d.mts +1 -1
- package/dist/transcriber/Transcriber.d.mts +1 -1
- package/dist/web-read/WebReadTool.d.mts +1 -1
- package/dist/web-search/WebSearchTool.d.mts +1 -1
- package/package.json +29 -1
- package/src/capabilities/Capabilities.ts +38 -0
- package/src/domain/Image.ts +68 -2
- package/src/domain/Items.ts +18 -1
- package/src/domain/Media.ts +66 -0
- package/src/domain/Music.ts +4 -3
- package/src/domain/Turn.ts +56 -0
- package/src/image-generator/ImageGenerator.ts +165 -0
- package/src/inbox/Inbox.test.ts +52 -0
- package/src/inbox/Inbox.ts +33 -0
- package/src/index.ts +6 -0
- package/src/messenger/Messenger.ts +293 -0
- package/src/messenger/MessengerAdapter.test.ts +179 -0
- package/src/messenger/MessengerAdapter.ts +189 -0
- package/src/messenger/MessengerError.ts +67 -0
- package/src/streaming/Multipart.ts +29 -0
- package/src/testing/MockMessenger.ts +147 -0
- package/dist/Image-BK8-4H6s.d.mts +0 -59
- package/dist/Image-BK8-4H6s.d.mts.map +0 -1
- package/dist/Items-SfUabNuB.d.mts.map +0 -1
- package/dist/Media-DwgpifPD.d.mts +0 -57
- package/dist/Media-DwgpifPD.d.mts.map +0 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { CurrentConversation, MessageId, Messenger } from "../messenger/Messenger.mjs";
|
|
2
|
+
import { splitForLimit, streamViaEdits } from "../messenger/MessengerAdapter.mjs";
|
|
3
|
+
import { Array, Data, Effect, Layer, Option, Ref, Stream } from "effect";
|
|
4
|
+
//#region src/testing/MockMessenger.ts
|
|
5
|
+
const Call = Data.taggedEnum();
|
|
6
|
+
const defaultLimits = {
|
|
7
|
+
maxText: 4096,
|
|
8
|
+
maxCaption: 1024
|
|
9
|
+
};
|
|
10
|
+
const bodyText = (msg) => msg.body._tag === "Text" ? Option.some(msg.body.text) : Option.none();
|
|
11
|
+
const buildService = (script, record, cursor, minted) => {
|
|
12
|
+
const limits = script.limits ?? defaultLimits;
|
|
13
|
+
const nextFailure = Ref.getAndUpdate(cursor, (n) => n + 1).pipe(Effect.flatMap((i) => Option.match(Option.fromNullishOr((script.failures ?? [])[i]), {
|
|
14
|
+
onNone: () => Effect.void,
|
|
15
|
+
onSome: Effect.fail
|
|
16
|
+
})));
|
|
17
|
+
const mint = Ref.updateAndGet(minted, (n) => n + 1).pipe(Effect.map((n) => MessageId(`m${n}`)));
|
|
18
|
+
const post = (msg) => Effect.gen(function* () {
|
|
19
|
+
const conversation = yield* CurrentConversation;
|
|
20
|
+
yield* record(Call.Post({
|
|
21
|
+
conversation,
|
|
22
|
+
message: msg
|
|
23
|
+
}));
|
|
24
|
+
yield* nextFailure;
|
|
25
|
+
const chunks = Option.match(bodyText(msg), {
|
|
26
|
+
onNone: () => 1,
|
|
27
|
+
onSome: (t) => splitForLimit(t, limits.maxText).length
|
|
28
|
+
});
|
|
29
|
+
return yield* Effect.map(Effect.forEach(Array.range(1, chunks), () => mint), Array.lastNonEmpty);
|
|
30
|
+
});
|
|
31
|
+
const edit = (msg, next) => record(Call.Edit({
|
|
32
|
+
message: msg,
|
|
33
|
+
next
|
|
34
|
+
})).pipe(Effect.andThen(nextFailure));
|
|
35
|
+
return {
|
|
36
|
+
events: script.events ?? Stream.empty,
|
|
37
|
+
post,
|
|
38
|
+
edit,
|
|
39
|
+
react: (msg, emoji) => record(Call.React({
|
|
40
|
+
message: msg,
|
|
41
|
+
emoji
|
|
42
|
+
})),
|
|
43
|
+
typing: Effect.gen(function* () {
|
|
44
|
+
const conversation = yield* CurrentConversation;
|
|
45
|
+
yield* record(Call.TypingStart({ conversation }));
|
|
46
|
+
yield* Effect.addFinalizer(() => record(Call.TypingStop({ conversation })));
|
|
47
|
+
}),
|
|
48
|
+
stream: streamViaEdits({
|
|
49
|
+
post,
|
|
50
|
+
edit,
|
|
51
|
+
limits
|
|
52
|
+
}, script.streamOptions),
|
|
53
|
+
limits
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
const makeUnsafe = (script) => {
|
|
57
|
+
const calls = Ref.makeUnsafe([]);
|
|
58
|
+
return {
|
|
59
|
+
service: buildService(script, (call) => Ref.update(calls, Array.append(call)), Ref.makeUnsafe(0), Ref.makeUnsafe(0)),
|
|
60
|
+
recorder: Ref.get(calls).pipe(Effect.map((c) => ({ calls: c })))
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
/** Layer registering the mock against the `Messenger` tag, plus its recorder. */
|
|
64
|
+
const layer = (script = {}) => {
|
|
65
|
+
const { service, recorder } = makeUnsafe(script);
|
|
66
|
+
return {
|
|
67
|
+
layer: Layer.succeed(Messenger, service),
|
|
68
|
+
recorder
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
/** Bare service value + recorder. Use with `Effect.provideService`. */
|
|
72
|
+
const make = (script = {}) => makeUnsafe(script);
|
|
73
|
+
//#endregion
|
|
74
|
+
export { Call, layer, make };
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=MockMessenger.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MockMessenger.mjs","names":["Arr"],"sources":["../../src/testing/MockMessenger.ts"],"sourcesContent":["import { Array as Arr, Data, Effect, Layer, Option, Ref, Stream } from \"effect\"\nimport {\n type ConversationRef,\n CurrentConversation,\n type InboundEvent,\n MessageId,\n type MessageRef,\n Messenger,\n type MessengerLimits,\n type MessengerService,\n type Outbound,\n} from \"../messenger/Messenger.js\"\nimport {\n type StreamViaEditsOptions,\n splitForLimit,\n streamViaEdits,\n} from \"../messenger/MessengerAdapter.js\"\nimport * as MessengerError from \"../messenger/MessengerError.js\"\n\n// ---------------------------------------------------------------------------\n// Call log\n// ---------------------------------------------------------------------------\n\n/**\n * One entry per outbound call. `Post` is logged once even when the text was\n * long enough to split, so a caller that rolled over on its own is\n * distinguishable from one that leaned on `post` to do it.\n */\nexport type Call = Data.TaggedEnum<{\n Post: { readonly conversation: ConversationRef; readonly message: Outbound }\n Edit: { readonly message: MessageRef; readonly next: Outbound }\n React: { readonly message: MessageRef; readonly emoji: string }\n TypingStart: { readonly conversation: ConversationRef }\n TypingStop: { readonly conversation: ConversationRef }\n}>\n\nexport const Call = Data.taggedEnum<Call>()\n\nexport type MockMessengerRecorder = {\n readonly calls: ReadonlyArray<Call>\n}\n\n// ---------------------------------------------------------------------------\n// Script\n// ---------------------------------------------------------------------------\n\nexport type MockMessengerScript = {\n /** Inbound events to replay. Empty by default. */\n readonly events?: Stream.Stream<InboundEvent, MessengerError.MessengerError>\n readonly limits?: MessengerLimits\n /**\n * Failures handed back one per `post` / `edit` call, in order; `undefined`\n * entries succeed, and everything past the end succeeds.\n */\n readonly failures?: ReadonlyArray<MessengerError.MessengerError | undefined>\n /** Passed through to `streamViaEdits`, which backs `stream`. */\n readonly streamOptions?: StreamViaEditsOptions\n}\n\nconst defaultLimits: MessengerLimits = { maxText: 4096, maxCaption: 1024 }\n\nconst bodyText = (msg: Outbound): Option.Option<string> =>\n msg.body._tag === \"Text\" ? Option.some(msg.body.text) : Option.none()\n\n// ---------------------------------------------------------------------------\n// Service builder\n// ---------------------------------------------------------------------------\n\nconst buildService = (\n script: MockMessengerScript,\n record: (call: Call) => Effect.Effect<void>,\n cursor: Ref.Ref<number>,\n minted: Ref.Ref<number>,\n): MessengerService => {\n const limits = script.limits ?? defaultLimits\n\n const nextFailure = Ref.getAndUpdate(cursor, (n) => n + 1).pipe(\n Effect.flatMap((i) =>\n Option.match(Option.fromNullishOr((script.failures ?? [])[i]), {\n onNone: () => Effect.void,\n onSome: Effect.fail<MessengerError.MessengerError>,\n }),\n ),\n )\n\n const mint = Ref.updateAndGet(minted, (n) => n + 1).pipe(Effect.map((n) => MessageId(`m${n}`)))\n\n const post: MessengerService[\"post\"] = (msg) =>\n Effect.gen(function* () {\n const conversation = yield* CurrentConversation\n yield* record(Call.Post({ conversation, message: msg }))\n yield* nextFailure\n // One id per chunk, mirroring an adapter that splits at the ceiling.\n const chunks = Option.match(bodyText(msg), {\n onNone: () => 1,\n onSome: (t) => splitForLimit(t, limits.maxText).length,\n })\n return yield* Effect.map(\n Effect.forEach(Arr.range(1, chunks), () => mint),\n Arr.lastNonEmpty,\n )\n })\n\n const edit: MessengerService[\"edit\"] = (msg, next) =>\n record(Call.Edit({ message: msg, next })).pipe(Effect.andThen(nextFailure))\n\n return {\n events: script.events ?? Stream.empty,\n post,\n edit,\n react: (msg, emoji) => record(Call.React({ message: msg, emoji })),\n typing: Effect.gen(function* () {\n const conversation = yield* CurrentConversation\n yield* record(Call.TypingStart({ conversation }))\n yield* Effect.addFinalizer(() => record(Call.TypingStop({ conversation })))\n }),\n stream: streamViaEdits({ post, edit, limits }, script.streamOptions),\n limits,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nconst makeUnsafe = (script: MockMessengerScript) => {\n const calls = Ref.makeUnsafe<ReadonlyArray<Call>>([])\n const service = buildService(\n script,\n (call) => Ref.update(calls, Arr.append(call)),\n Ref.makeUnsafe(0),\n Ref.makeUnsafe(0),\n )\n return {\n service,\n recorder: Ref.get(calls).pipe(Effect.map((c): MockMessengerRecorder => ({ calls: c }))),\n }\n}\n\n/** Layer registering the mock against the `Messenger` tag, plus its recorder. */\nexport const layer = (script: MockMessengerScript = {}) => {\n const { service, recorder } = makeUnsafe(script)\n return { layer: Layer.succeed(Messenger, service), recorder }\n}\n\n/** Bare service value + recorder. Use with `Effect.provideService`. */\nexport const make = (script: MockMessengerScript = {}) => makeUnsafe(script)\n"],"mappings":";;;;AAoCA,MAAa,OAAO,KAAK,WAAiB;AAuB1C,MAAM,gBAAiC;CAAE,SAAS;CAAM,YAAY;AAAK;AAEzE,MAAM,YAAY,QAChB,IAAI,KAAK,SAAS,SAAS,OAAO,KAAK,IAAI,KAAK,IAAI,IAAI,OAAO,KAAK;AAMtE,MAAM,gBACJ,QACA,QACA,QACA,WACqB;CACrB,MAAM,SAAS,OAAO,UAAU;CAEhC,MAAM,cAAc,IAAI,aAAa,SAAS,MAAM,IAAI,CAAC,CAAC,CAAC,KACzD,OAAO,SAAS,MACd,OAAO,MAAM,OAAO,eAAe,OAAO,YAAY,CAAC,EAAA,CAAG,EAAE,GAAG;EAC7D,cAAc,OAAO;EACrB,QAAQ,OAAO;CACjB,CAAC,CACH,CACF;CAEA,MAAM,OAAO,IAAI,aAAa,SAAS,MAAM,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,KAAK,MAAM,UAAU,IAAI,GAAG,CAAC,CAAC;CAE9F,MAAM,QAAkC,QACtC,OAAO,IAAI,aAAa;EACtB,MAAM,eAAe,OAAO;EAC5B,OAAO,OAAO,KAAK,KAAK;GAAE;GAAc,SAAS;EAAI,CAAC,CAAC;EACvD,OAAO;EAEP,MAAM,SAAS,OAAO,MAAM,SAAS,GAAG,GAAG;GACzC,cAAc;GACd,SAAS,MAAM,cAAc,GAAG,OAAO,OAAO,CAAC,CAAC;EAClD,CAAC;EACD,OAAO,OAAO,OAAO,IACnB,OAAO,QAAQA,MAAI,MAAM,GAAG,MAAM,SAAS,IAAI,GAC/CA,MAAI,YACN;CACF,CAAC;CAEH,MAAM,QAAkC,KAAK,SAC3C,OAAO,KAAK,KAAK;EAAE,SAAS;EAAK;CAAK,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,WAAW,CAAC;CAE5E,OAAO;EACL,QAAQ,OAAO,UAAU,OAAO;EAChC;EACA;EACA,QAAQ,KAAK,UAAU,OAAO,KAAK,MAAM;GAAE,SAAS;GAAK;EAAM,CAAC,CAAC;EACjE,QAAQ,OAAO,IAAI,aAAa;GAC9B,MAAM,eAAe,OAAO;GAC5B,OAAO,OAAO,KAAK,YAAY,EAAE,aAAa,CAAC,CAAC;GAChD,OAAO,OAAO,mBAAmB,OAAO,KAAK,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC;EAC5E,CAAC;EACD,QAAQ,eAAe;GAAE;GAAM;GAAM;EAAO,GAAG,OAAO,aAAa;EACnE;CACF;AACF;AAMA,MAAM,cAAc,WAAgC;CAClD,MAAM,QAAQ,IAAI,WAAgC,CAAC,CAAC;CAOpD,OAAO;EACL,SAPc,aACd,SACC,SAAS,IAAI,OAAO,OAAOA,MAAI,OAAO,IAAI,CAAC,GAC5C,IAAI,WAAW,CAAC,GAChB,IAAI,WAAW,CAAC,CAGV;EACN,UAAU,IAAI,IAAI,KAAK,CAAC,CAAC,KAAK,OAAO,KAAK,OAA8B,EAAE,OAAO,EAAE,EAAE,CAAC;CACxF;AACF;;AAGA,MAAa,SAAS,SAA8B,CAAC,MAAM;CACzD,MAAM,EAAE,SAAS,aAAa,WAAW,MAAM;CAC/C,OAAO;EAAE,OAAO,MAAM,QAAQ,WAAW,OAAO;EAAG;CAAS;AAC9D;;AAGA,MAAa,QAAQ,SAA8B,CAAC,MAAM,WAAW,MAAM"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as AudioChunk } from "../Audio-
|
|
1
|
+
import { n as AudioChunk } from "../Audio-_nGR4V0X.mjs";
|
|
2
2
|
import { CommonGenerateMusicRequest, CommonStreamGenerateMusicRequest, GenerateResult, MusicStreamEvent, audioEvent } from "../domain/Music.mjs";
|
|
3
3
|
import { MusicGenerator, MusicInteractiveSession } from "../music-generator/MusicGenerator.mjs";
|
|
4
4
|
import { Effect, Layer } from "effect";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as HistoryItem } from "../Items-
|
|
1
|
+
import { o as HistoryItem } from "../Items-C7MyrYPX.mjs";
|
|
2
2
|
import { Turn } from "../domain/Turn.mjs";
|
|
3
3
|
import { LanguageModel, LanguageModelService } from "../language-model/LanguageModel.mjs";
|
|
4
4
|
import { Duration, Effect, Layer } from "effect";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as AudioChunk, t as AudioBlob } from "../Audio-
|
|
1
|
+
import { n as AudioChunk, t as AudioBlob } from "../Audio-_nGR4V0X.mjs";
|
|
2
2
|
import { CommonStreamSynthesizeRequest, CommonSynthesizeDialogueRequest, CommonSynthesizeRequest, MultiSpeakerTts, SpeechSynthesizer, TtsIncrementalText } from "../speech-synthesizer/SpeechSynthesizer.mjs";
|
|
3
3
|
import { Effect, Layer } from "effect";
|
|
4
4
|
//#region src/testing/MockSpeechSynthesizer.d.ts
|
package/dist/tool/Approval.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as ToolResult } from "../ToolResult-
|
|
3
|
-
import { t as ToolEvent } from "../ToolEvent-
|
|
1
|
+
import { y as ToolCall } from "../Items-C7MyrYPX.mjs";
|
|
2
|
+
import { t as ToolResult } from "../ToolResult-BsYQRjmW.mjs";
|
|
3
|
+
import { t as ToolEvent } from "../ToolEvent-Di4a723B.mjs";
|
|
4
4
|
import { Data, Duration, Effect, Queue, Scope, Stream } from "effect";
|
|
5
5
|
declare namespace Approval_d_exports {
|
|
6
6
|
export { ApprovalDecision, ApprovalMapEntry, FromQueueOptions, ToolCallPlan, Verdict, approvalRequested, approve, fromMap, fromQueue, reject, splitApprovalDecisions };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { o as HistoryItem,
|
|
2
|
-
import { t as ToolResult } from "../ToolResult-
|
|
1
|
+
import { o as HistoryItem, y as ToolCall } from "../Items-C7MyrYPX.mjs";
|
|
2
|
+
import { t as ToolResult } from "../ToolResult-BsYQRjmW.mjs";
|
|
3
3
|
declare namespace HistoryCheck_d_exports {
|
|
4
4
|
export { cancelAllPending, findUnansweredCalls, isReconciled };
|
|
5
5
|
}
|
package/dist/tool/Tool.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as providerToolsOf, C as fromEffectSchema, D as make, E as isProviderTool, M as toDescriptors, N as withName, O as noInput, P as withRun, S as fail, T as interaction, a as Emit, b as descriptorsOf, c as SignalTool, d as ToolE, f as ToolError, g as ToolValidationError, h as ToolR, i as DecodeResult, j as signal, k as provider, l as Tool, m as ToolInputSchema, n as AnyTool, o as InteractionTool, p as ToolFailed, r as DecodableTool, s as ProviderTool, t as AnyLocalTool, u as ToolDescriptor, v as decodeArgs, w as fromStandardSchema, x as execute, y as decodeCallInput } from "../Tool-
|
|
1
|
+
import { A as providerToolsOf, C as fromEffectSchema, D as make, E as isProviderTool, M as toDescriptors, N as withName, O as noInput, P as withRun, S as fail, T as interaction, a as Emit, b as descriptorsOf, c as SignalTool, d as ToolE, f as ToolError, g as ToolValidationError, h as ToolR, i as DecodeResult, j as signal, k as provider, l as Tool, m as ToolInputSchema, n as AnyTool, o as InteractionTool, p as ToolFailed, r as DecodableTool, s as ProviderTool, t as AnyLocalTool, u as ToolDescriptor, v as decodeArgs, w as fromStandardSchema, x as execute, y as decodeCallInput } from "../Tool-BF78QWtn.mjs";
|
|
2
2
|
export { AnyLocalTool, AnyTool, DecodableTool, DecodeResult, Emit, InteractionTool, ProviderTool, SignalTool, Tool, ToolDescriptor, ToolE, ToolError, ToolFailed, ToolInputSchema, ToolR, ToolValidationError, decodeArgs, decodeCallInput, descriptorsOf, execute, fail, fromEffectSchema, fromStandardSchema, interaction, isProviderTool, make, noInput, provider, providerToolsOf, signal, toDescriptors, withName, withRun };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as isProgress, i as isOutput, r as isApprovalRequested, t as ToolEvent } from "../ToolEvent-
|
|
1
|
+
import { a as isProgress, i as isOutput, r as isApprovalRequested, t as ToolEvent } from "../ToolEvent-Di4a723B.mjs";
|
|
2
2
|
export { ToolEvent, isApprovalRequested, isOutput, isProgress };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as executionError, c as isOk, d as toToolCallOutput, f as validationError, i as denied, l as nonLocalTool, o as failed, r as cancelled, s as isFailure, t as ToolResult, u as serializeValue } from "../ToolResult-
|
|
1
|
+
import { a as executionError, c as isOk, d as toToolCallOutput, f as validationError, i as denied, l as nonLocalTool, o as failed, r as cancelled, s as isFailure, t as ToolResult, u as serializeValue } from "../ToolResult-BsYQRjmW.mjs";
|
|
2
2
|
export { ToolResult, cancelled, denied, executionError, failed, isFailure, isOk, nonLocalTool, serializeValue, toToolCallOutput, validationError };
|
package/dist/tool/Toolkit.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { S as wrap, _ as fromArray, a as ToolMap, b as namespace, c as ToolkitR, d as appendToolResults, f as collectResults, g as descriptors, h as describeFailures, i as NoDuplicateNames, m as continueWithResults, n as ExecuteOptions, o as Toolkit, p as compose, r as Middleware, s as ToolkitE, t as DuplicateToolName, u as UniqueTools, v as make, x as run, y as makeNamespaced } from "../Toolkit-
|
|
1
|
+
import { S as wrap, _ as fromArray, a as ToolMap, b as namespace, c as ToolkitR, d as appendToolResults, f as collectResults, g as descriptors, h as describeFailures, i as NoDuplicateNames, m as continueWithResults, n as ExecuteOptions, o as Toolkit, p as compose, r as Middleware, s as ToolkitE, t as DuplicateToolName, u as UniqueTools, v as make, x as run, y as makeNamespaced } from "../Toolkit-DAjJ9Tvl.mjs";
|
|
2
2
|
export { DuplicateToolName, ExecuteOptions, Middleware, NoDuplicateNames, ToolMap, Toolkit, ToolkitE, ToolkitR, UniqueTools, appendToolResults, collectResults, compose, continueWithResults, describeFailures, descriptors, fromArray, make, makeNamespaced, namespace, run, wrap };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as AiError } from "../AiError-eLV9t1lU.mjs";
|
|
2
|
-
import { a as AudioSource, r as AudioFormat } from "../Audio-
|
|
2
|
+
import { a as AudioSource, r as AudioFormat } from "../Audio-_nGR4V0X.mjs";
|
|
3
3
|
import { TranscriptEvent, TranscriptResult } from "../domain/Transcript.mjs";
|
|
4
4
|
import { Context, Effect, Stream } from "effect";
|
|
5
5
|
declare namespace Transcriber_d_exports {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-uai/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Low-level primitives (loop, conversation, items, tools, streaming codecs) for building AI agents with Effect.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -106,10 +106,26 @@
|
|
|
106
106
|
"types": "./dist/embedding-model/EmbeddingModel.d.mts",
|
|
107
107
|
"import": "./dist/embedding-model/EmbeddingModel.mjs"
|
|
108
108
|
},
|
|
109
|
+
"./ImageGenerator": {
|
|
110
|
+
"types": "./dist/image-generator/ImageGenerator.d.mts",
|
|
111
|
+
"import": "./dist/image-generator/ImageGenerator.mjs"
|
|
112
|
+
},
|
|
109
113
|
"./LanguageModel": {
|
|
110
114
|
"types": "./dist/language-model/LanguageModel.d.mts",
|
|
111
115
|
"import": "./dist/language-model/LanguageModel.mjs"
|
|
112
116
|
},
|
|
117
|
+
"./Messenger": {
|
|
118
|
+
"types": "./dist/messenger/Messenger.d.mts",
|
|
119
|
+
"import": "./dist/messenger/Messenger.mjs"
|
|
120
|
+
},
|
|
121
|
+
"./MessengerAdapter": {
|
|
122
|
+
"types": "./dist/messenger/MessengerAdapter.d.mts",
|
|
123
|
+
"import": "./dist/messenger/MessengerAdapter.mjs"
|
|
124
|
+
},
|
|
125
|
+
"./MessengerError": {
|
|
126
|
+
"types": "./dist/messenger/MessengerError.d.mts",
|
|
127
|
+
"import": "./dist/messenger/MessengerError.mjs"
|
|
128
|
+
},
|
|
113
129
|
"./MusicGenerator": {
|
|
114
130
|
"types": "./dist/music-generator/MusicGenerator.d.mts",
|
|
115
131
|
"import": "./dist/music-generator/MusicGenerator.mjs"
|
|
@@ -162,6 +178,10 @@
|
|
|
162
178
|
"types": "./dist/web-search/WebSearchTool.d.mts",
|
|
163
179
|
"import": "./dist/web-search/WebSearchTool.mjs"
|
|
164
180
|
},
|
|
181
|
+
"./Inbox": {
|
|
182
|
+
"types": "./dist/inbox/Inbox.d.mts",
|
|
183
|
+
"import": "./dist/inbox/Inbox.mjs"
|
|
184
|
+
},
|
|
165
185
|
"./Loop": {
|
|
166
186
|
"types": "./dist/loop/Loop.d.mts",
|
|
167
187
|
"import": "./dist/loop/Loop.mjs"
|
|
@@ -214,6 +234,10 @@
|
|
|
214
234
|
"types": "./dist/streaming/Lines.d.mts",
|
|
215
235
|
"import": "./dist/streaming/Lines.mjs"
|
|
216
236
|
},
|
|
237
|
+
"./Multipart": {
|
|
238
|
+
"types": "./dist/streaming/Multipart.d.mts",
|
|
239
|
+
"import": "./dist/streaming/Multipart.mjs"
|
|
240
|
+
},
|
|
217
241
|
"./SSE": {
|
|
218
242
|
"types": "./dist/streaming/SSE.d.mts",
|
|
219
243
|
"import": "./dist/streaming/SSE.mjs"
|
|
@@ -230,6 +254,10 @@
|
|
|
230
254
|
"types": "./dist/testing/MockProvider.d.mts",
|
|
231
255
|
"import": "./dist/testing/MockProvider.mjs"
|
|
232
256
|
},
|
|
257
|
+
"./testing/MockMessenger": {
|
|
258
|
+
"types": "./dist/testing/MockMessenger.d.mts",
|
|
259
|
+
"import": "./dist/testing/MockMessenger.mjs"
|
|
260
|
+
},
|
|
233
261
|
"./testing/MockMusicGenerator": {
|
|
234
262
|
"types": "./dist/testing/MockMusicGenerator.d.mts",
|
|
235
263
|
"import": "./dist/testing/MockMusicGenerator.mjs"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Effect } from "effect"
|
|
2
|
+
import type { ContentBlock, HistoryItem } from "../domain/Items.js"
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Structured event emitted when a provider adapter drops a Common
|
|
@@ -79,3 +80,40 @@ export const warnDroppedWhen = <T>(
|
|
|
79
80
|
value: T | undefined,
|
|
80
81
|
warning: Omit<CapabilityWarning, "_tag" | "value">,
|
|
81
82
|
): Effect.Effect<void> => (value === undefined ? Effect.void : warnDropped({ ...warning, value }))
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Warn when history carries a content block this provider's wire has no
|
|
86
|
+
* place for, which its encoder therefore omits.
|
|
87
|
+
*
|
|
88
|
+
* History is provider-agnostic, so a turn one provider produced can be
|
|
89
|
+
* replayed into another. A block only one provider can express
|
|
90
|
+
* (`output_image`, which needs an assistant-role image part) then reaches
|
|
91
|
+
* an encoder with nothing to map it to. Omitting is right, since failing
|
|
92
|
+
* would break replaying a mixed history just to continue the text, but it
|
|
93
|
+
* should not be silent.
|
|
94
|
+
*
|
|
95
|
+
* Call once from the effectful request path; the block encoders stay pure.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* yield* warnDroppedBlocks(history, "output_image", {
|
|
100
|
+
* provider: "anthropic",
|
|
101
|
+
* capability: "output_image",
|
|
102
|
+
* reason: "Assistant messages carry no image here. Convert with `imagesAsInput` to send it as user content.",
|
|
103
|
+
* })
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export const warnDroppedBlocks = (
|
|
107
|
+
history: ReadonlyArray<HistoryItem>,
|
|
108
|
+
type: ContentBlock["type"],
|
|
109
|
+
warning: Omit<CapabilityWarning, "_tag" | "field" | "value">,
|
|
110
|
+
): Effect.Effect<void> => {
|
|
111
|
+
const count = history.reduce(
|
|
112
|
+
(n, item) =>
|
|
113
|
+
n + (item.type === "message" ? item.content.filter((b) => b.type === type).length : 0),
|
|
114
|
+
0,
|
|
115
|
+
)
|
|
116
|
+
return count === 0
|
|
117
|
+
? Effect.void
|
|
118
|
+
: warnDropped({ ...warning, field: type, value: `${count} block(s)` })
|
|
119
|
+
}
|
package/src/domain/Image.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import { Schema } from "effect"
|
|
2
|
-
import type {
|
|
1
|
+
import { Result, Schema } from "effect"
|
|
2
|
+
import type {
|
|
3
|
+
AspectRatio,
|
|
4
|
+
Dimensions,
|
|
5
|
+
MediaBase64,
|
|
6
|
+
MediaBytes,
|
|
7
|
+
MediaSource,
|
|
8
|
+
MediaUrl,
|
|
9
|
+
Watermark,
|
|
10
|
+
} from "./Media.js"
|
|
11
|
+
import { parseAspectRatio, round16 } from "./Media.js"
|
|
3
12
|
|
|
4
13
|
/**
|
|
5
14
|
* Image MIME types AI providers typically accept. The first four are the
|
|
@@ -70,6 +79,63 @@ export const imageBytes = (bytes: Uint8Array, mimeType: ImageMimeType): ImageByt
|
|
|
70
79
|
mimeType,
|
|
71
80
|
})
|
|
72
81
|
|
|
82
|
+
/** Cross-modality; lives in `Media.ts` because video generation shares it. */
|
|
83
|
+
export type { AspectRatio, Dimensions } from "./Media.js"
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Resolution tier, roughly the short edge in pixels. A tier rather than
|
|
87
|
+
* a pixel pair: adapters whose wire takes exact dimensions derive them
|
|
88
|
+
* from the tier and the aspect ratio. Image-typed on purpose, video
|
|
89
|
+
* models tier by scan height instead.
|
|
90
|
+
*/
|
|
91
|
+
export type ImageResolution = "1K" | "2K" | "4K"
|
|
92
|
+
|
|
93
|
+
const SHORT_EDGE: Record<ImageResolution, number> = { "1K": 1024, "2K": 2048, "4K": 4096 }
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Turn the portable ratio and tier into pixels: the tier is the short
|
|
97
|
+
* edge, the long edge follows the ratio. `undefined` when neither was
|
|
98
|
+
* asked for, which the caller sends as "no size" so the endpoint picks.
|
|
99
|
+
*
|
|
100
|
+
* Adapters whose wire wants `"WxH"` format the pair; those wanting an
|
|
101
|
+
* object send it as is. Whether the result is in range for a given model
|
|
102
|
+
* is the server's call: per-model limits churn and we do not table them.
|
|
103
|
+
*/
|
|
104
|
+
export const pixelsOf = (request: {
|
|
105
|
+
readonly aspectRatio?: AspectRatio
|
|
106
|
+
readonly resolution?: ImageResolution
|
|
107
|
+
}): Result.Result<Dimensions | undefined, string> =>
|
|
108
|
+
request.aspectRatio === undefined && request.resolution === undefined
|
|
109
|
+
? Result.succeed(undefined)
|
|
110
|
+
: Result.map(parseAspectRatio(request.aspectRatio ?? "1:1"), ([w, h]) => {
|
|
111
|
+
const short = SHORT_EDGE[request.resolution ?? "1K"]
|
|
112
|
+
return w >= h
|
|
113
|
+
? { width: round16((short * w) / h), height: short }
|
|
114
|
+
: { width: short, height: round16((short * h) / w) }
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Per-image extras a provider reported and this type has no field for:
|
|
119
|
+
* pixel dimensions, a file name, a revised prompt. Opaque here, and a
|
|
120
|
+
* shared slot, so a provider keys its data under its own name
|
|
121
|
+
* (`{ fal: … }`, `{ openai: … }`) and reads only that key. Each provider
|
|
122
|
+
* package ships a typed reader; the framework never interprets it.
|
|
123
|
+
*
|
|
124
|
+
* Not promoted to real fields because the providers disagree on what
|
|
125
|
+
* they report. Only some fal endpoints return dimensions, and neither
|
|
126
|
+
* OpenAI's Images API nor Gemini returns them at all.
|
|
127
|
+
*/
|
|
128
|
+
export type ProviderData = unknown
|
|
129
|
+
|
|
130
|
+
/** One image off a generation call, plus what the provider stamped into it. */
|
|
131
|
+
export type GeneratedImage = {
|
|
132
|
+
readonly image: ImageSource
|
|
133
|
+
/** Set only when the provider applies one. */
|
|
134
|
+
readonly watermark?: Watermark
|
|
135
|
+
/** {@link ProviderData}: per-image extras, keyed by provider name. */
|
|
136
|
+
readonly providerData?: ProviderData
|
|
137
|
+
}
|
|
138
|
+
|
|
73
139
|
export const isImageUrl = Schema.is(ImageUrlSource)
|
|
74
140
|
export const isImageBase64 = Schema.is(ImageBase64Source)
|
|
75
141
|
export const isImageBytes = Schema.is(ImageBytesSource)
|
package/src/domain/Items.ts
CHANGED
|
@@ -88,6 +88,22 @@ export const OutputText = Schema.Struct({
|
|
|
88
88
|
})
|
|
89
89
|
export type OutputText = typeof OutputText.Type
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Model-emitted image. The counterpart to {@link InputImage}: same
|
|
93
|
+
* `ImageSource`, so an image the model drew goes straight back into the
|
|
94
|
+
* next turn with no conversion.
|
|
95
|
+
*
|
|
96
|
+
* How the pixels were produced is not modelled here. A provider may draw
|
|
97
|
+
* them itself, as an image part of the turn, or reach a hosted tool that
|
|
98
|
+
* draws them; either way the fact is the same, and enabling it is
|
|
99
|
+
* provider-specific.
|
|
100
|
+
*/
|
|
101
|
+
export const OutputImage = Schema.Struct({
|
|
102
|
+
type: Schema.Literal("output_image"),
|
|
103
|
+
source: ImageSource,
|
|
104
|
+
})
|
|
105
|
+
export type OutputImage = typeof OutputImage.Type
|
|
106
|
+
|
|
91
107
|
/**
|
|
92
108
|
* Model-emitted refusal. Distinct from `output_text`: the model declined
|
|
93
109
|
* to answer rather than producing normal output. Pair with
|
|
@@ -100,7 +116,7 @@ export const Refusal = Schema.Struct({
|
|
|
100
116
|
})
|
|
101
117
|
export type Refusal = typeof Refusal.Type
|
|
102
118
|
|
|
103
|
-
export const ContentBlock = Schema.Union([InputText, InputImage, OutputText, Refusal])
|
|
119
|
+
export const ContentBlock = Schema.Union([InputText, InputImage, OutputText, OutputImage, Refusal])
|
|
104
120
|
export type ContentBlock = typeof ContentBlock.Type
|
|
105
121
|
|
|
106
122
|
export const Role = Schema.Literals(["user", "assistant", "system"])
|
|
@@ -176,6 +192,7 @@ export type HistoryItem = typeof HistoryItem.Type
|
|
|
176
192
|
export const isInputText = Schema.is(InputText)
|
|
177
193
|
export const isInputImage = Schema.is(InputImage)
|
|
178
194
|
export const isOutputText = Schema.is(OutputText)
|
|
195
|
+
export const isOutputImage = Schema.is(OutputImage)
|
|
179
196
|
export const isRefusal = Schema.is(Refusal)
|
|
180
197
|
|
|
181
198
|
export const isMessage = Schema.is(Message)
|
package/src/domain/Media.ts
CHANGED
|
@@ -31,6 +31,72 @@
|
|
|
31
31
|
* they're a separate union (`FileRef`) added when needed.
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
+
import { Result } from "effect"
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Watermark kind a provider embedded in generated media. Shared across
|
|
38
|
+
* modalities (audio, image). No provider exposes metadata beyond the
|
|
39
|
+
* kind, so a bare literal union is enough.
|
|
40
|
+
*/
|
|
41
|
+
export type Watermark = "synthid" | "c2pa" | (string & {})
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Requested shape of generated visual media, width to height. Shared by
|
|
45
|
+
* image and video generation: the listed ratios are the ones providers
|
|
46
|
+
* accept as literals, and the `(string & {})` tail keeps a
|
|
47
|
+
* newly-supported ratio working without an SDK update. Which ratios a
|
|
48
|
+
* given model accepts is not checked here; the provider rejects what it
|
|
49
|
+
* cannot render and the adapter translates that error.
|
|
50
|
+
*
|
|
51
|
+
* Resolution is NOT shared: image models tier by short edge
|
|
52
|
+
* (`ImageResolution`), video models by scan height. Each modality types
|
|
53
|
+
* its own.
|
|
54
|
+
*/
|
|
55
|
+
export type AspectRatio =
|
|
56
|
+
| "1:1"
|
|
57
|
+
| "2:3"
|
|
58
|
+
| "3:2"
|
|
59
|
+
| "3:4"
|
|
60
|
+
| "4:3"
|
|
61
|
+
| "4:5"
|
|
62
|
+
| "5:4"
|
|
63
|
+
| "9:16"
|
|
64
|
+
| "16:9"
|
|
65
|
+
| "21:9"
|
|
66
|
+
| "1:4"
|
|
67
|
+
| "4:1"
|
|
68
|
+
| "1:8"
|
|
69
|
+
| "8:1"
|
|
70
|
+
| (string & {})
|
|
71
|
+
|
|
72
|
+
/** Exact pixels, for adapters whose wire takes dimensions rather than a ratio. */
|
|
73
|
+
export type Dimensions = {
|
|
74
|
+
readonly width: number
|
|
75
|
+
readonly height: number
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const positive = (n: number | undefined): n is number =>
|
|
79
|
+
n !== undefined && Number.isFinite(n) && n > 0
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Read `"W:H"` as a pair. Fails when the ratio is not arithmetic, which
|
|
83
|
+
* the `(string & {})` tail on {@link AspectRatio} lets through: a caller
|
|
84
|
+
* asking for `"cinematic"` gets a message rather than NaN pixels. The
|
|
85
|
+
* failure is a plain string so this file stays free of provider
|
|
86
|
+
* vocabulary; each adapter wraps it in its own error.
|
|
87
|
+
*/
|
|
88
|
+
export const parseAspectRatio = (
|
|
89
|
+
ratio: AspectRatio,
|
|
90
|
+
): Result.Result<readonly [number, number], string> => {
|
|
91
|
+
const [w, h, ...rest] = ratio.split(":").map(Number)
|
|
92
|
+
return positive(w) && positive(h) && rest.length === 0
|
|
93
|
+
? Result.succeed([w, h] as const)
|
|
94
|
+
: Result.fail(`aspectRatio "${ratio}" must read "W:H" with positive numbers.`)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Several image endpoints require both edges to be multiples of 16. */
|
|
98
|
+
export const round16 = (n: number): number => Math.max(16, Math.round(n / 16) * 16)
|
|
99
|
+
|
|
34
100
|
export type MediaUrl<M extends string = string> = {
|
|
35
101
|
readonly _tag: "url"
|
|
36
102
|
readonly url: string
|
package/src/domain/Music.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Duration } from "effect"
|
|
2
2
|
import type { AudioBlob, AudioChunk, AudioFormat } from "./Audio.js"
|
|
3
|
+
import type { Watermark } from "./Media.js"
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Prompt fragment with a relative weight. Native to Lyria RealTime
|
|
@@ -95,10 +96,10 @@ export const controlInput = (action: MusicSessionControl): MusicSessionInput =>
|
|
|
95
96
|
|
|
96
97
|
/**
|
|
97
98
|
* Watermark kind on the response. SynthID is mandatory on Lyria; C2PA
|
|
98
|
-
* is opt-in on ElevenLabs.
|
|
99
|
-
*
|
|
99
|
+
* is opt-in on ElevenLabs. Lives in `Media.ts` since image providers
|
|
100
|
+
* report the same kinds; re-exported here unchanged.
|
|
100
101
|
*/
|
|
101
|
-
export type Watermark
|
|
102
|
+
export type { Watermark } from "./Media.js"
|
|
102
103
|
|
|
103
104
|
/**
|
|
104
105
|
* Labelled section with absolute timing. Populated when the provider
|
package/src/domain/Turn.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Data, Effect, Result, Schema, Stream, pipe } from "effect"
|
|
2
2
|
import * as StructuredFormat from "../structured-format/StructuredFormat.js"
|
|
3
|
+
import type { ImageSource } from "./Image.js"
|
|
3
4
|
import {
|
|
4
5
|
type Annotation,
|
|
5
6
|
HistoryItem,
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
ToolCall,
|
|
10
11
|
ToolCallOutput,
|
|
11
12
|
Usage,
|
|
13
|
+
isOutputImage,
|
|
12
14
|
isOutputText,
|
|
13
15
|
isReasoning,
|
|
14
16
|
isRefusal,
|
|
@@ -49,6 +51,12 @@ export type Turn = typeof Turn.Type
|
|
|
49
51
|
* `WebSearchCall`: lifecycle of a provider-executed web search within the
|
|
50
52
|
* turn. Fires only when the turn grounds against search; absent otherwise.
|
|
51
53
|
*
|
|
54
|
+
* `ImageOutput`: an image the model produced, whether it drew it as part
|
|
55
|
+
* of its turn or reached a hosted tool for it. `partialIndex` marks a
|
|
56
|
+
* preview frame from providers that stream them; the finished image
|
|
57
|
+
* arrives without one and is also on `TurnComplete.turn` as an
|
|
58
|
+
* `OutputImage` block.
|
|
59
|
+
*
|
|
52
60
|
* `CitationAdded`: a citation attached to the answer, emitted incrementally
|
|
53
61
|
* where the provider streams citations. Providers that bundle citations emit
|
|
54
62
|
* none of these; their citations still arrive on `TurnComplete.turn`
|
|
@@ -66,6 +74,11 @@ export type TurnEvent = Data.TaggedEnum<{
|
|
|
66
74
|
readonly query?: string
|
|
67
75
|
readonly action?: "search" | "open_page" | "find_in_page"
|
|
68
76
|
}
|
|
77
|
+
ImageOutput: {
|
|
78
|
+
readonly image: ImageSource
|
|
79
|
+
/** Set only on a preview frame, counting from 0. Absent means finished. */
|
|
80
|
+
readonly partialIndex?: number
|
|
81
|
+
}
|
|
69
82
|
CitationAdded: { readonly annotation: Annotation }
|
|
70
83
|
TurnComplete: { readonly turn: Turn }
|
|
71
84
|
}>
|
|
@@ -109,6 +122,49 @@ export const assistantTexts = (turn: Turn): ReadonlyArray<string> =>
|
|
|
109
122
|
*/
|
|
110
123
|
export const assistantText = (turn: Turn): string => assistantTexts(turn).join("")
|
|
111
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Every image the model produced this turn, in order. The counterpart to
|
|
127
|
+
* {@link assistantTexts}: each is an `ImageSource`, so it can be written
|
|
128
|
+
* to disk or passed straight back as an `input_image` on the next turn.
|
|
129
|
+
*/
|
|
130
|
+
export const assistantImages = (turn: Turn): ReadonlyArray<ImageSource> =>
|
|
131
|
+
assistantMessages(turn)
|
|
132
|
+
.flatMap((m) => m.content)
|
|
133
|
+
.filter(isOutputImage)
|
|
134
|
+
.map((b) => b.source)
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Rewrite assistant `output_image` blocks into a user message carrying
|
|
138
|
+
* the same pictures as `input_image`, so another provider can look at
|
|
139
|
+
* what this one drew.
|
|
140
|
+
*
|
|
141
|
+
* Only Gemini's wire has an assistant-role image part; every other
|
|
142
|
+
* adapter omits an `output_image` on replay and says so. Moving it to a
|
|
143
|
+
* user message is the conversion that makes it portable, and it is
|
|
144
|
+
* yours to make rather than the adapter's: "the assistant drew this" and
|
|
145
|
+
* "here is an image, look at it" are different claims, and silently
|
|
146
|
+
* swapping one for the other behind your back would be the wrong kind of
|
|
147
|
+
* helpful.
|
|
148
|
+
*
|
|
149
|
+
* Items with no images pass through untouched, and the new user message
|
|
150
|
+
* follows the assistant message it came from.
|
|
151
|
+
*/
|
|
152
|
+
export const imagesAsInput = (history: ReadonlyArray<HistoryItem>): ReadonlyArray<HistoryItem> =>
|
|
153
|
+
history.flatMap((item) => {
|
|
154
|
+
if (item.type !== "message" || item.role !== "assistant") return [item]
|
|
155
|
+
const images = item.content.filter(isOutputImage)
|
|
156
|
+
return images.length === 0
|
|
157
|
+
? [item]
|
|
158
|
+
: [
|
|
159
|
+
item,
|
|
160
|
+
{
|
|
161
|
+
type: "message" as const,
|
|
162
|
+
role: "user" as const,
|
|
163
|
+
content: images.map((b) => ({ type: "input_image" as const, source: b.source })),
|
|
164
|
+
},
|
|
165
|
+
]
|
|
166
|
+
})
|
|
167
|
+
|
|
112
168
|
/**
|
|
113
169
|
* Every citation annotation attached to the turn's assistant `output_text`
|
|
114
170
|
* blocks, in order. The flat view of a grounded turn's sources, whether the
|