@atomoz/workflows-nodes 0.1.16 → 0.1.17

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/index.cjs CHANGED
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -150,7 +151,9 @@ var HttpGetInputNode = {
150
151
 
151
152
  // src/nodes/inputs/http/get/function.ts
152
153
  var HttpGetInputNodeFunction = async (params) => {
153
- const { request, fieldValues } = params;
154
+ const { $field: _$field, $req, $inputs: _$inputs, $vars: _$vars } = params;
155
+ const request = $req || params.request;
156
+ const fieldValues = params.fieldValues || {};
154
157
  const { queryParams: configQueryParams, headers: configHeaders } = fieldValues || {};
155
158
  const actualData = {
156
159
  queryParams: request?.query || {},
@@ -277,7 +280,9 @@ var HttpPostInputNode = {
277
280
 
278
281
  // src/nodes/inputs/http/post/function.ts
279
282
  var HttpPostInputNodeFunction = (params) => {
280
- const { request, fieldValues } = params;
283
+ const { $field: _$field, $req, $inputs: _$inputs, $vars: _$vars } = params;
284
+ const request = $req || params.request;
285
+ const fieldValues = params.fieldValues || {};
281
286
  const { queryParams: configQueryParams, headers: configHeaders, body: configBody } = fieldValues || {};
282
287
  if (request.method !== "POST") {
283
288
  throw new Error("M\xE9todo HTTP inv\xE1lido");
@@ -323,7 +328,9 @@ var HttpPostInputNodeSchema = import_zod3.z.object({
323
328
 
324
329
  // src/nodes/inputs/chat/chat.ts
325
330
  var ChatInputNodeFunction = (params) => {
326
- const { request, fieldValues } = params;
331
+ const { $field: _$field, $req, $inputs: _$inputs, $vars: _$vars } = params;
332
+ const request = $req || params.request;
333
+ const fieldValues = params.fieldValues || {};
327
334
  const { message: configMessage, chatId: configChatId } = fieldValues || {};
328
335
  const actualData = {
329
336
  message: request?.message ?? configMessage ?? "",
@@ -376,7 +383,8 @@ var ChatInputNode = {
376
383
 
377
384
  // src/nodes/inputs/manual/trigger.ts
378
385
  var ManualTriggerNodeFunction = (params) => {
379
- const { fieldValues } = params || {};
386
+ const { $field: _$field, $req: _$req, $inputs: _$inputs, $vars: _$vars } = params;
387
+ const fieldValues = params.fieldValues || {};
380
388
  return fieldValues || {};
381
389
  };
382
390
  var ManualTriggerNode = {
@@ -413,11 +421,84 @@ var ManualTriggerNode = {
413
421
  ]
414
422
  };
415
423
 
424
+ // src/nodes/inputs/cron/trigger.ts
425
+ var CronTriggerNodeFunction = (params) => {
426
+ const { $req } = params;
427
+ const triggerData = $req || {};
428
+ const fieldValues = params.fieldValues || {};
429
+ return {
430
+ triggeredAt: triggerData.triggeredAt || (/* @__PURE__ */ new Date()).toISOString(),
431
+ scheduleId: triggerData.scheduleId || null,
432
+ cronExpression: fieldValues.cronExpression || null,
433
+ timezone: fieldValues.timezone || "America/Sao_Paulo",
434
+ success: true
435
+ };
436
+ };
437
+ var CronTriggerNode = {
438
+ label: "Cron Trigger",
439
+ type: "CronTrigger",
440
+ category: "input",
441
+ icon: "\u23F0",
442
+ description: "Dispara fluxo automaticamente baseado em express\xE3o cron",
443
+ tags: {
444
+ execution: "async",
445
+ group: "Custom"
446
+ },
447
+ fields: [
448
+ {
449
+ id: "cronExpression",
450
+ label: "Express\xE3o Cron",
451
+ type: "string",
452
+ required: true,
453
+ placeholder: "0 9 * * * (todos os dias \xE0s 9h)"
454
+ },
455
+ {
456
+ id: "timezone",
457
+ label: "Timezone",
458
+ type: "select",
459
+ defaultValue: "America/Sao_Paulo",
460
+ options: [
461
+ { label: "S\xE3o Paulo (GMT-3)", value: "America/Sao_Paulo" },
462
+ { label: "UTC", value: "UTC" },
463
+ { label: "New York (GMT-5)", value: "America/New_York" },
464
+ { label: "Los Angeles (GMT-8)", value: "America/Los_Angeles" },
465
+ { label: "London (GMT+0)", value: "Europe/London" }
466
+ ]
467
+ },
468
+ {
469
+ id: "triggeredAt",
470
+ label: "Triggered At",
471
+ type: "string",
472
+ typeable: false,
473
+ handle: {
474
+ type: "output",
475
+ label: "Triggered At",
476
+ name: "triggeredAt",
477
+ fieldType: "string"
478
+ }
479
+ },
480
+ {
481
+ id: "scheduleId",
482
+ label: "Schedule ID",
483
+ type: "string",
484
+ typeable: false,
485
+ handle: {
486
+ type: "output",
487
+ label: "Schedule ID",
488
+ name: "scheduleId",
489
+ fieldType: "string"
490
+ }
491
+ }
492
+ ]
493
+ };
494
+
416
495
  // src/nodes/processors/concat.ts
417
496
  var import_zod4 = require("zod");
418
- var ConcatNodeFunction = (inputs) => {
419
- const input1 = inputs.input1 || "";
420
- const input2 = inputs.input2 || "";
497
+ var ConcatNodeFunction = (params) => {
498
+ const { $field: _$field, $req: _$req, $inputs: _$inputs, $vars: _$vars } = params;
499
+ const inputs_resolved = params.inputs || params || {};
500
+ const input1 = inputs_resolved.input1 || "";
501
+ const input2 = inputs_resolved.input2 || "";
421
502
  const result = `${input1}${input2}`;
422
503
  return {
423
504
  output: result,
@@ -597,8 +678,12 @@ var OutputNode = {
597
678
 
598
679
  // src/nodes/outputs/chat/output.ts
599
680
  var ChatOutputNodeFunction = async (params) => {
600
- const { inputs, fieldValues, stream, emitter } = params || {};
601
- const content = inputs?.data ?? fieldValues?.data ?? "";
681
+ const { $field: _$field, $req: _$req, $inputs: _$inputs, $vars: _$vars } = params;
682
+ const inputs_resolved = params.inputs || {};
683
+ const fieldValues = params.fieldValues || {};
684
+ const stream = params.stream;
685
+ const emitter = params.emitter;
686
+ const content = inputs_resolved?.data ?? fieldValues?.data ?? "";
602
687
  if (stream && emitter) {
603
688
  try {
604
689
  emitter.emitDone({ content });
@@ -785,44 +870,12 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
785
870
  throw new Error('Model config deve conter "model" e "integrationId"');
786
871
  }
787
872
  const { model, integrationId } = modelConfig;
788
- const client = new import_graphql_request.GraphQLClient(GRAPHQL_ENDPOINT, {
789
- headers: {
790
- Authorization: `Bearer ${authToken}`,
791
- "x-tenant-id": "65d62c52-0c09-473a-8895-359afbed3f5a"
792
- }
793
- });
794
- let integrationData;
795
- try {
796
- const response = await client.request(
797
- GET_INTEGRATIONS_QUERY,
798
- {
799
- where: {
800
- id: {
801
- eq: integrationId
802
- }
803
- }
804
- }
805
- );
806
- if (!response.getIntegrations?.data?.[0]) {
807
- throw new Error(`Integra\xE7\xE3o ${integrationId} n\xE3o encontrada`);
808
- }
809
- integrationData = response.getIntegrations.data[0];
810
- } catch (error) {
811
- console.error("Erro ao buscar integra\xE7\xE3o:", error);
812
- throw new Error(
813
- `Falha ao buscar integra\xE7\xE3o: ${error instanceof Error ? error.message : "Erro desconhecido"}`
814
- );
815
- }
816
- const apiKey = integrationData.data?.["token"] || integrationData.data?.["token"];
817
- if (!apiKey) {
818
- throw new Error(`API Key n\xE3o encontrada na integra\xE7\xE3o ${integrationId}`);
819
- }
820
- const provider = integrationData.data?.provider?.toLowerCase() || inferProviderFromModel(model);
873
+ const provider = "gemini";
821
874
  switch (provider) {
822
875
  case "gemini":
823
876
  return new import_google_gauth.ChatGoogle({
824
877
  model: "gemini-flash-latest",
825
- apiKey,
878
+ apiKey: "AIzaSyAWS9GhesWxG4uTdJRQbBziMB1diXtXtlI",
826
879
  streaming
827
880
  });
828
881
  case "openai":
@@ -846,21 +899,14 @@ async function createLLMFromModel(modelConfig, authToken, streaming = false) {
846
899
  );
847
900
  }
848
901
  }
849
- function inferProviderFromModel(model) {
850
- const modelLower = model.toLowerCase();
851
- if (modelLower.includes("gemini") || modelLower.includes("palm")) {
852
- return "gemini";
853
- }
854
- if (modelLower.includes("gpt") || modelLower.includes("o1") || modelLower.includes("o3")) {
855
- return "openai";
856
- }
857
- return "openrouter";
858
- }
859
902
 
860
903
  // src/nodes/ia/agent/function.ts
861
904
  var IaAgentNodeFunction = async (inputs) => {
862
- const { model, tools, systemMessage, name, message } = inputs.fieldValues;
905
+ const { $field: _$field, $req: _$req, $inputs: _$inputs, $vars: _$vars } = inputs;
906
+ const { model, tools, systemMessage, name, message } = inputs.fieldValues || {};
863
907
  const authToken = inputs.authToken;
908
+ const stream = Boolean(inputs?.stream);
909
+ const emitter = inputs?.emitter;
864
910
  if (!name) {
865
911
  throw new Error("Agent 'name' is required. Please provide a unique name for the agent in the node properties.");
866
912
  }
@@ -882,8 +928,7 @@ IMPORTANT: You must base your response on the last message in the conversation h
882
928
  if (!authToken) {
883
929
  throw new Error("Auth token is required to instantiate LLM from integration");
884
930
  }
885
- const streaming = Boolean(inputs?.stream);
886
- llmInstance = await createLLMFromModel(model, authToken, streaming);
931
+ llmInstance = await createLLMFromModel(model, authToken, stream);
887
932
  } else if (typeof model?.bindTools === "function") {
888
933
  llmInstance = model;
889
934
  } else {
@@ -899,22 +944,70 @@ IMPORTANT: You must base your response on the last message in the conversation h
899
944
  if (message) {
900
945
  try {
901
946
  const { HumanMessage: HumanMessage2 } = await import("@langchain/core/messages");
902
- const result = await agent.invoke({
903
- messages: [new HumanMessage2(message)]
904
- });
905
- if (result?.messages && result.messages.length > 0) {
906
- const lastMessage = result.messages[result.messages.length - 1];
907
- const content = lastMessage?.content;
908
- if (typeof content === "string") {
909
- output = content;
910
- } else if (Array.isArray(content)) {
911
- output = content.map((part) => {
912
- if (typeof part === "string") return part;
913
- if (part?.type === "text") return part.text;
914
- return "";
915
- }).filter(Boolean).join("\n");
916
- } else {
917
- output = "";
947
+ if (stream && emitter) {
948
+ const streamIterator = await agent.stream({
949
+ messages: [new HumanMessage2(message)]
950
+ });
951
+ let lastMessages = [];
952
+ const sentContents = /* @__PURE__ */ new Set();
953
+ for await (const step of streamIterator) {
954
+ if (step && typeof step === "object") {
955
+ for (const [key, value] of Object.entries(step)) {
956
+ if (value && typeof value === "object" && "messages" in value) {
957
+ const messages = value.messages;
958
+ if (Array.isArray(messages)) {
959
+ lastMessages = messages;
960
+ for (const msg of messages) {
961
+ const content = msg?.content;
962
+ const contentStr = typeof content === "string" ? content : Array.isArray(content) ? content.map((p) => p.type === "text" ? p.text : "").filter(Boolean).join("") : "";
963
+ if (contentStr && !sentContents.has(contentStr)) {
964
+ sentContents.add(contentStr);
965
+ if (emitter?.emitDelta) {
966
+ emitter.emitDelta({
967
+ content: contentStr,
968
+ actor: name,
969
+ isAgent: true,
970
+ isTool: false
971
+ });
972
+ }
973
+ }
974
+ }
975
+ }
976
+ }
977
+ }
978
+ }
979
+ }
980
+ if (lastMessages.length > 0) {
981
+ const lastMessage = lastMessages[lastMessages.length - 1];
982
+ const content = lastMessage?.content;
983
+ if (typeof content === "string") {
984
+ output = content;
985
+ } else if (Array.isArray(content)) {
986
+ output = content.map((part) => {
987
+ if (typeof part === "string") return part;
988
+ if (part?.type === "text") return part.text;
989
+ return "";
990
+ }).filter(Boolean).join("\n");
991
+ }
992
+ }
993
+ } else {
994
+ const result = await agent.invoke({
995
+ messages: [new HumanMessage2(message)]
996
+ });
997
+ if (result?.messages && result.messages.length > 0) {
998
+ const lastMessage = result.messages[result.messages.length - 1];
999
+ const content = lastMessage?.content;
1000
+ if (typeof content === "string") {
1001
+ output = content;
1002
+ } else if (Array.isArray(content)) {
1003
+ output = content.map((part) => {
1004
+ if (typeof part === "string") return part;
1005
+ if (part?.type === "text") return part.text;
1006
+ return "";
1007
+ }).filter(Boolean).join("\n");
1008
+ } else {
1009
+ output = "";
1010
+ }
918
1011
  }
919
1012
  }
920
1013
  } catch (error) {
@@ -1063,8 +1156,9 @@ var extractFinalResponse = (messages) => {
1063
1156
  }
1064
1157
  return "No response generated.";
1065
1158
  };
1066
- var AiSupervisorNodeFunction = async (fieldValues) => {
1067
- const outer = fieldValues ?? {};
1159
+ var AiSupervisorNodeFunction = async (params) => {
1160
+ const { $field: _$field, $req: _$req, $inputs: _$inputs, $vars: _$vars } = params;
1161
+ const outer = params ?? {};
1068
1162
  const inner = outer && typeof outer === "object" && outer.fieldValues && typeof outer.fieldValues === "object" ? outer.fieldValues : {};
1069
1163
  const model = inner.model ?? outer.model;
1070
1164
  const agents = inner.agents ?? outer.agents;
@@ -1284,7 +1378,9 @@ var schemas = {
1284
1378
  };
1285
1379
 
1286
1380
  // src/nodes/ia/tool/function.ts
1287
- var AiToolNodeFunction = async (fieldValues) => {
1381
+ var AiToolNodeFunction = async (params) => {
1382
+ const { $field: _$field, $req: _$req, $inputs: _$inputs, $vars: _$vars } = params;
1383
+ const fieldValues = params.fieldValues || params;
1288
1384
  const { name, description, nodeFunction, nodeType, originalNodeData, workflowService, currentResults } = fieldValues;
1289
1385
  const schema = schemas[nodeType] || CustomToolSchema;
1290
1386
  const dynamicTool = (0, import_tools.tool)(
@@ -1327,9 +1423,12 @@ var IaMessageNodeSchema = import_zod8.z.object({
1327
1423
  message: import_zod8.z.string().describe("User message to send to the LLM")
1328
1424
  });
1329
1425
  var IaMessageNodeFunction = async (inputs) => {
1426
+ const { $field: _$field, $req: _$req, $inputs: _$inputs_var, $vars: _$vars } = inputs;
1330
1427
  const fieldValues = inputs.fieldValues || inputs;
1331
1428
  const { model, systemMessage, message } = fieldValues;
1332
1429
  const authToken = inputs.authToken;
1430
+ const stream = Boolean(inputs?.stream);
1431
+ const emitter = inputs?.emitter;
1333
1432
  if (!model) {
1334
1433
  throw new Error("Model is required");
1335
1434
  }
@@ -1339,10 +1438,9 @@ var IaMessageNodeFunction = async (inputs) => {
1339
1438
  let llmInstance;
1340
1439
  if (model?.model && model?.integrationId) {
1341
1440
  if (!authToken) {
1342
- throw new Error("Auth token is required to instantiate LLM from integration2 ");
1441
+ throw new Error("Auth token is required to instantiate LLM from integration");
1343
1442
  }
1344
- const streaming = Boolean(inputs?.stream);
1345
- llmInstance = await createLLMFromModel(model, authToken, streaming);
1443
+ llmInstance = await createLLMFromModel(model, authToken, stream);
1346
1444
  } else {
1347
1445
  llmInstance = model;
1348
1446
  }
@@ -1352,6 +1450,29 @@ var IaMessageNodeFunction = async (inputs) => {
1352
1450
  }
1353
1451
  messages.push(["human", message]);
1354
1452
  try {
1453
+ if (stream && emitter) {
1454
+ let fullContent = "";
1455
+ const streamResponse = await llmInstance.stream(messages);
1456
+ for await (const chunk of streamResponse) {
1457
+ const chunkContent = typeof chunk.content === "string" ? chunk.content : chunk.content?.text || "";
1458
+ if (chunkContent) {
1459
+ fullContent += chunkContent;
1460
+ if (emitter?.emitDelta) {
1461
+ emitter.emitDelta({
1462
+ content: chunkContent,
1463
+ actor: "IaMessageNode",
1464
+ isAgent: false,
1465
+ isTool: false
1466
+ });
1467
+ }
1468
+ }
1469
+ }
1470
+ return {
1471
+ output: fullContent,
1472
+ response: fullContent,
1473
+ fullResponse: { content: fullContent }
1474
+ };
1475
+ }
1355
1476
  const response = await llmInstance.invoke(messages);
1356
1477
  return {
1357
1478
  output: response.content,
@@ -1583,19 +1704,75 @@ var WhatsappMessageTriggerNode = {
1583
1704
 
1584
1705
  // src/nodes/processors/custom-code.ts
1585
1706
  var NodeFunction = (params) => {
1586
- const { inputValue, fieldValues } = params;
1587
- const { customCode } = fieldValues;
1588
- if (!customCode) {
1589
- return inputValue;
1707
+ let input = params?.inputValue ?? params?.input;
1708
+ const context = params && params.fieldValues ? params.fieldValues : params || {};
1709
+ let customCode = context?.customCode ?? params?.customCode;
1710
+ if (input === void 0 && Array.isArray(context?.fields)) {
1711
+ const firstInputField = context.fields.find((f) => f?.handle?.type === "input");
1712
+ if (firstInputField && firstInputField.id) {
1713
+ const key = String(firstInputField.id);
1714
+ if (params && Object.prototype.hasOwnProperty.call(params, key)) input = params[key];
1715
+ else if (context && Object.prototype.hasOwnProperty.call(context, key)) input = context[key];
1716
+ else if (firstInputField.value !== void 0) input = firstInputField.value;
1717
+ }
1718
+ }
1719
+ const looksLikeCode = (code) => {
1720
+ if (typeof code !== "string") return false;
1721
+ const c = code.trim();
1722
+ if (c.length < 3) return false;
1723
+ return /(return\s+|=>|function\s*\(|;|\n|\{|\})/.test(c);
1724
+ };
1725
+ if (typeof customCode === "string" && !looksLikeCode(customCode)) {
1726
+ if (input === void 0) input = customCode;
1727
+ customCode = "";
1728
+ }
1729
+ if (!customCode || typeof customCode === "string" && customCode.trim() === "") {
1730
+ return input;
1590
1731
  }
1591
1732
  try {
1592
- const customFunction = new Function("input", "context", "request", "params", customCode);
1593
- const result = customFunction(inputValue, fieldValues, params.request, params);
1733
+ const $inputs = params?.results || {};
1734
+ const $vars = context && context.variables || params?.variables || void 0;
1735
+ const __placeholders = params?.__codePlaceholders ?? context?.__codePlaceholders;
1736
+ const customFunction = new Function("input", "context", "request", "params", "$inputs", "$vars", "__placeholders", customCode);
1737
+ const result = customFunction(input, context, params?.request, params, $inputs, $vars, __placeholders);
1594
1738
  return result;
1595
1739
  } catch (error) {
1596
1740
  throw new Error(`Erro ao executar c\xF3digo customizado: ${error instanceof Error ? error.message : "Erro desconhecido"}`);
1597
1741
  }
1598
1742
  };
1743
+ var CustomNodeFunction = (params) => {
1744
+ const context = params && params.fieldValues ? params.fieldValues : params || {};
1745
+ const customCode = context?.customCode;
1746
+ if (!customCode || typeof customCode === "string" && customCode.trim() === "") {
1747
+ throw new Error("CustomNode sem c\xF3digo configurado");
1748
+ }
1749
+ const fields = Array.isArray(context?.fields) ? context.fields : [];
1750
+ const $field = {};
1751
+ fields.forEach((field) => {
1752
+ const fieldId = field?.id;
1753
+ if (!fieldId) return;
1754
+ let value;
1755
+ if (params && Object.prototype.hasOwnProperty.call(params, fieldId)) {
1756
+ value = params[fieldId];
1757
+ } else if (field.handle && field.handle.name && params && Object.prototype.hasOwnProperty.call(params, field.handle.name)) {
1758
+ value = params[field.handle.name];
1759
+ } else if (field.value !== void 0) {
1760
+ value = field.value;
1761
+ } else if (field.defaultValue !== void 0) {
1762
+ value = field.defaultValue;
1763
+ }
1764
+ $field[fieldId] = value;
1765
+ });
1766
+ try {
1767
+ const $inputs = params?.results || {};
1768
+ const $vars = context && context.variables || params?.variables || void 0;
1769
+ const customFunction = new Function("$field", "context", "request", "params", "$inputs", "$vars", customCode);
1770
+ const result = customFunction($field, context, params?.request, params, $inputs, $vars);
1771
+ return result;
1772
+ } catch (error) {
1773
+ throw new Error(`Erro ao executar CustomNode: ${error instanceof Error ? error.message : "Erro desconhecido"}`);
1774
+ }
1775
+ };
1599
1776
  var CustomCodeNode = {
1600
1777
  label: "Custom Code",
1601
1778
  type: "CustomCodeNode",
@@ -1608,7 +1785,13 @@ var CustomCodeNode = {
1608
1785
  label: "C\xF3digo Customizado",
1609
1786
  type: "code",
1610
1787
  required: false,
1611
- placeholder: '// Seu c\xF3digo JavaScript aqui\n// Use "input" para acessar o valor de entrada\n// Use "context" para acessar os dados do n\xF3\nreturn input;',
1788
+ placeholder: '// Seu c\xF3digo JavaScript aqui\n// Use "input" para acessar o valor de entrada\n// Use "context" para acessar os dados do n\xF3\nreturn input;'
1789
+ },
1790
+ {
1791
+ id: "input",
1792
+ label: "Input",
1793
+ type: "any",
1794
+ required: false,
1612
1795
  handle: {
1613
1796
  type: "input",
1614
1797
  label: "Input",
@@ -1637,6 +1820,7 @@ var CustomCodeNode = {
1637
1820
  var nodes = [
1638
1821
  ChatInputNode,
1639
1822
  ManualTriggerNode,
1823
+ CronTriggerNode,
1640
1824
  HttpGetInputNode,
1641
1825
  // HttpPostInputNode,
1642
1826
  // TransformNode,
@@ -1755,6 +1939,7 @@ var nodeFunctions = {
1755
1939
  HttpGetInput: HttpGetInputNodeFunction,
1756
1940
  HttpPostInput: HttpPostInputNodeFunction,
1757
1941
  ManualTrigger: ManualTriggerNodeFunction,
1942
+ CronTrigger: CronTriggerNodeFunction,
1758
1943
  HttpOutput: HttpOutputNodeFunction,
1759
1944
  ConcatNode: ConcatNodeFunction,
1760
1945
  IaMessageNode: IaMessageNodeFunction,
@@ -1763,7 +1948,8 @@ var nodeFunctions = {
1763
1948
  AiSupervisorNode: AiSupervisorNodeFunction,
1764
1949
  WhatsappNode: WhatsappStartChatFunction,
1765
1950
  WhatsappSendMessageNode: WhatsappSendMessageFunction,
1766
- CustomCodeNode: NodeFunction
1951
+ CustomCodeNode: NodeFunction,
1952
+ CustomNode: CustomNodeFunction
1767
1953
  };
1768
1954
  var node_functions_default = nodeFunctions;
1769
1955